From e0d58349de2d91d79c29321e9430383960a16d7f Mon Sep 17 00:00:00 2001 From: Simon Vieille Date: Wed, 17 Mar 2021 12:44:02 +0100 Subject: [PATCH] add blog category CRUD --- .gitignore | 1 + assets/js/addons/editor.js | 2 +- config/packages/twig.yaml | 1 + package.json | 2 +- public/vendor/tinymce | 1 + .../Blog/CategoryAdminController.php | 99 ++++++++++++++++++- src/Doctrine/Timestampable.php | 4 +- src/Entity/Blog/Category.php | 42 +++++++- src/Entity/Blog/Post.php | 42 +++++++- .../{Entity.php => EntityInterface.php} | 2 +- src/Entity/User.php | 7 +- .../EntityManager/EntityManagerEvent.php | 8 +- src/Factory/Blog/CategoryFactory.php | 18 ++++ src/Form/Blog/CategoryType.php | 79 +++++++++++++++ src/Manager/EntityManager.php | 12 +-- .../Blog/CategoryRepositoryQuery.php | 3 +- src/Repository/Blog/PostRepositoryQuery.php | 17 +++- src/Repository/RepositoryQuery.php | 24 +++-- templates/admin/layout.html.twig | 2 +- templates/blog/category_admin/_form.html.twig | 17 ++++ templates/blog/category_admin/edit.html.twig | 57 +++++++++++ templates/blog/category_admin/index.html.twig | 78 ++++++++++----- templates/blog/category_admin/new.html.twig | 39 ++++++++ templates/blog/category_admin/show.html.twig | 83 ++++++++++++++++ yarn.lock | 8 +- 25 files changed, 577 insertions(+), 71 deletions(-) create mode 120000 public/vendor/tinymce rename src/Entity/{Entity.php => EntityInterface.php} (56%) create mode 100644 src/Factory/Blog/CategoryFactory.php create mode 100644 src/Form/Blog/CategoryType.php create mode 100644 templates/blog/category_admin/_form.html.twig create mode 100644 templates/blog/category_admin/edit.html.twig create mode 100644 templates/blog/category_admin/new.html.twig create mode 100644 templates/blog/category_admin/show.html.twig diff --git a/.gitignore b/.gitignore index ba27aaf..281da24 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ /.env.*.local /config/secrets/prod/prod.decrypt.private.php /public/bundles/ +/src/Command/TestCommand.php /var/ /vendor/ ###< symfony/framework-bundle ### diff --git a/assets/js/addons/editor.js b/assets/js/addons/editor.js index 53c5997..75c06f0 100644 --- a/assets/js/addons/editor.js +++ b/assets/js/addons/editor.js @@ -5,7 +5,7 @@ module.exports = function() { tinymce.init({ selector: '*[data-tinymce]', - base_url: '/nm/tinymce/', + base_url: '/vendor/tinymce/', cache_suffix: '?v=4.1.6', language: 'fr_FR', plugins: 'print preview importcss searchreplace visualblocks visualchars fullscreen template table charmap hr pagebreak nonbreaking toc insertdatetime advlist lists wordcount textpattern noneditable help charmap quickbars', diff --git a/config/packages/twig.yaml b/config/packages/twig.yaml index b3cdf30..90c5321 100644 --- a/config/packages/twig.yaml +++ b/config/packages/twig.yaml @@ -1,2 +1,3 @@ twig: default_path: '%kernel.project_dir%/templates' + form_themes: ['bootstrap_4_layout.html.twig'] diff --git a/package.json b/package.json index 3537b19..c154a13 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "jquery": "^3.6.0", "popper.js": "^1.16.0", "qrcodejs": "^1.0.0", - "tinymce": "^5.2.0", + "tinymce": "^5.7.1", "vanillajs-datepicker": "^1.1.2", "zxcvbn": "^4.4.2" } diff --git a/public/vendor/tinymce b/public/vendor/tinymce new file mode 120000 index 0000000..3da1341 --- /dev/null +++ b/public/vendor/tinymce @@ -0,0 +1 @@ +../../node_modules/tinymce \ No newline at end of file diff --git a/src/Controller/Blog/CategoryAdminController.php b/src/Controller/Blog/CategoryAdminController.php index 9403182..d9fc9bd 100644 --- a/src/Controller/Blog/CategoryAdminController.php +++ b/src/Controller/Blog/CategoryAdminController.php @@ -3,6 +3,13 @@ namespace App\Controller\Blog; use App\Controller\Admin\AdminController; +use App\Entity\Blog\Category as Entity; +use App\Factory\Blog\CategoryFactory as EntityFactory; +use App\Form\Blog\CategoryType as EntityType; +use App\Manager\EntityManager; +use App\Repository\Blog\CategoryRepositoryQuery as RepositoryQuery; +use App\Repository\Blog\PostRepositoryQuery; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Annotation\Route; @@ -12,14 +19,102 @@ use Symfony\Component\Routing\Annotation\Route; class CategoryAdminController extends AdminController { /** - * @Route("/", name="admin_blog_category_index") + * @Route("/{page}", name="admin_blog_category_index", requirements={"page": "\d+"}) */ - public function index(): Response + public function index(int $page = 1, RepositoryQuery $query, Request $request): Response { + $pager = $query->paginate($page); + return $this->render('blog/category_admin/index.html.twig', [ + 'pager' => $pager, ]); } + /** + * @Route("/new", name="admin_blog_category_new") + */ + public function new(EntityFactory $factory, EntityManager $entityManager, Request $request): Response + { + $entity = $factory->create(); + $form = $this->createForm(EntityType::class, $entity); + + if ($request->isMethod('POST')) { + $form->handleRequest($request); + + if ($form->isValid()) { + $entityManager->create($entity)->flush()->clear(); + $this->addFlash('success', 'Donnée enregistrée.'); + + return $this->redirectToRoute('admin_blog_category_edit', [ + 'entity' => $entity->getId(), + ]); + } + $this->addFlash('warning', 'Le formulaire est invalide.'); + } + + return $this->render('blog/category_admin/new.html.twig', [ + 'form' => $form->createView(), + ]); + } + + /** + * @Route("/edit/{entity}", name="admin_blog_category_edit") + */ + public function edit(Entity $entity, EntityManager $entityManager, Request $request): Response + { + $form = $this->createForm(EntityType::class, $entity); + + if ($request->isMethod('POST')) { + $form->handleRequest($request); + + if ($form->isValid()) { + $entityManager->update($entity)->flush()->clear(); + $this->addFlash('success', 'Donnée enregistrée.'); + + return $this->redirectToRoute('admin_blog_category_edit', [ + 'entity' => $entity->getId(), + ]); + } + $this->addFlash('warning', 'Le formulaire est invalide.'); + } + + return $this->render('blog/category_admin/edit.html.twig', [ + 'form' => $form->createView(), + 'entity' => $entity, + ]); + } + + /** + * @Route("/show/{entity}", name="admin_blog_category_show") + */ + public function show(Entity $entity, PostRepositoryQuery $postQuery): Response + { + $posts = $postQuery->create() + ->orderBy('.publishedAt', 'DESC') + ->inCategory($entity) + ->paginate(1, 10) + ; + + return $this->render('blog/category_admin/show.html.twig', [ + 'entity' => $entity, + 'posts' => $posts, + ]); + } + + /** + * @Route("/delete/{entity}", name="admin_blog_category_delete", methods={"DELETE"}) + */ + public function delete(Entity $entity, EntityManager $entityManager, Request $request): Response + { + if ($this->isCsrfTokenValid('delete'.$entity->getId(), $request->request->get('_token'))) { + $entityManager->delete($entity)->flush()->clear(); + + $this->addFlash('success', 'Données supprimées.'); + } + + return $this->redirectToRoute('admin_blog_category_index'); + } + public function getSection(): string { return 'blog_category'; diff --git a/src/Doctrine/Timestampable.php b/src/Doctrine/Timestampable.php index 4109114..6fafc6e 100644 --- a/src/Doctrine/Timestampable.php +++ b/src/Doctrine/Timestampable.php @@ -38,7 +38,7 @@ trait Timestampable return $this; } - public function getCreatedAt():?\DateTime + public function getCreatedAt(): ?\DateTime { return $this->createdAt; } @@ -50,7 +50,7 @@ trait Timestampable return $this; } - public function getUpdatedAt():?\DateTime + public function getUpdatedAt(): ?\DateTime { return $this->updatedAt; } diff --git a/src/Entity/Blog/Category.php b/src/Entity/Blog/Category.php index efdde93..4324f31 100644 --- a/src/Entity/Blog/Category.php +++ b/src/Entity/Blog/Category.php @@ -2,13 +2,16 @@ namespace App\Entity\Blog; +use App\Entity\EntityInterface; use App\Repository\Blog\CategoryRepository; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity(repositoryClass=CategoryRepository::class) */ -class Category +class Category implements EntityInterface { /** * @ORM\Id @@ -37,6 +40,16 @@ class Category */ private $slug; + /** + * @ORM\ManyToMany(targetEntity=Post::class, mappedBy="categories") + */ + private $posts; + + public function __construct() + { + $this->posts = new ArrayCollection(); + } + public function getId(): ?int { return $this->id; @@ -89,4 +102,31 @@ class Category return $this; } + + /** + * @return Collection|Post[] + */ + public function getPosts(): Collection + { + return $this->posts; + } + + public function addPost(Post $post): self + { + if (!$this->posts->contains($post)) { + $this->posts[] = $post; + $post->addCategory($this); + } + + return $this; + } + + public function removePost(Post $post): self + { + if ($this->posts->removeElement($post)) { + $post->removeCategory($this); + } + + return $this; + } } diff --git a/src/Entity/Blog/Post.php b/src/Entity/Blog/Post.php index d89c9cb..27d463d 100644 --- a/src/Entity/Blog/Post.php +++ b/src/Entity/Blog/Post.php @@ -2,16 +2,20 @@ namespace App\Entity\Blog; +use App\Doctrine\Timestampable; +use App\Entity\EntityInterface; use App\Entity\User; use App\Repository\Blog\PostRepository; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; -use App\Doctrine\Timestampable; /** * @ORM\Entity(repositoryClass=PostRepository::class) */ -class Post +class Post implements EntityInterface { + use Timestampable; /** * @ORM\Id * @ORM\GeneratedValue @@ -69,7 +73,15 @@ class Post */ private $author; - use Timestampable; + /** + * @ORM\ManyToMany(targetEntity=Category::class, inversedBy="posts") + */ + private $categories; + + public function __construct() + { + $this->categories = new ArrayCollection(); + } public function getId(): ?int { @@ -195,4 +207,28 @@ class Post return $this; } + + /** + * @return Collection|Category[] + */ + public function getCategories(): Collection + { + return $this->categories; + } + + public function addCategory(Category $category): self + { + if (!$this->categories->contains($category)) { + $this->categories[] = $category; + } + + return $this; + } + + public function removeCategory(Category $category): self + { + $this->categories->removeElement($category); + + return $this; + } } diff --git a/src/Entity/Entity.php b/src/Entity/EntityInterface.php similarity index 56% rename from src/Entity/Entity.php rename to src/Entity/EntityInterface.php index f6ad59b..72e60b8 100644 --- a/src/Entity/Entity.php +++ b/src/Entity/EntityInterface.php @@ -2,6 +2,6 @@ namespace App\Entity; -interface Entity +interface EntityInterface { } diff --git a/src/Entity/User.php b/src/Entity/User.php index b56c63d..8d03289 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -2,6 +2,7 @@ namespace App\Entity; +use App\Doctrine\Timestampable; use App\Entity\Blog\Post; use App\Repository\UserRepository; use Doctrine\Common\Collections\ArrayCollection; @@ -10,14 +11,14 @@ use Doctrine\ORM\Mapping as ORM; use Scheb\TwoFactorBundle\Model\Google\TwoFactorInterface; use Scheb\TwoFactorBundle\Model\Totp\TotpConfiguration; use Symfony\Component\Security\Core\User\UserInterface; -use App\Doctrine\Timestampable; /** * @ORM\Entity(repositoryClass=UserRepository::class) * @ORM\Table(name="`user`") */ -class User implements UserInterface, TwoFactorInterface, Entity +class User implements UserInterface, TwoFactorInterface, EntityInterface { + use Timestampable; /** * @ORM\Id * @ORM\GeneratedValue @@ -76,8 +77,6 @@ class User implements UserInterface, TwoFactorInterface, Entity $this->posts = new ArrayCollection(); } - use Timestampable; - public function getId(): ?int { return $this->id; diff --git a/src/Event/EntityManager/EntityManagerEvent.php b/src/Event/EntityManager/EntityManagerEvent.php index f858324..29cf9e3 100644 --- a/src/Event/EntityManager/EntityManagerEvent.php +++ b/src/Event/EntityManager/EntityManagerEvent.php @@ -2,7 +2,7 @@ namespace App\Event\EntityManager; -use App\Entity\Entity; +use App\Entity\EntityInterface; use Symfony\Contracts\EventDispatcher\Event; /** @@ -16,14 +16,14 @@ class EntityManagerEvent extends Event const UPDATE_EVENT = 'entity_manager_event.update'; const DELETE_EVENT = 'entity_manager_event.delete'; - protected Entity $entity; + protected EntityInterface $entity; - public function __construct(Entity $entity) + public function __construct(EntityInterface $entity) { $this->entity = $entity; } - public function getEntity(): Entity + public function getEntity(): EntityInterface { return $this->entity; } diff --git a/src/Factory/Blog/CategoryFactory.php b/src/Factory/Blog/CategoryFactory.php new file mode 100644 index 0000000..eb21c80 --- /dev/null +++ b/src/Factory/Blog/CategoryFactory.php @@ -0,0 +1,18 @@ + + */ +class CategoryFactory +{ + public function create(): Category + { + return new Category(); + } +} diff --git a/src/Form/Blog/CategoryType.php b/src/Form/Blog/CategoryType.php new file mode 100644 index 0000000..48e17d2 --- /dev/null +++ b/src/Form/Blog/CategoryType.php @@ -0,0 +1,79 @@ +add( + 'title', + TextType::class, + [ + 'label' => 'Titre', + 'required' => true, + 'attr' => [ + ], + 'constraints' => [ + new NotBlank(), + ], + ] + ); + + $builder->add( + 'subTitle', + TextareaType::class, + [ + 'label' => 'Sous-titre', + 'required' => false, + 'attr' => [ + ], + 'constraints' => [ + ], + ] + ); + + $builder->add( + 'description', + TextareaType::class, + [ + 'label' => 'Description', + 'required' => false, + 'attr' => [ + 'data-tinymce' => '', + ], + 'constraints' => [ + ], + ] + ); + + $builder->add( + 'slug', + TextType::class, + [ + 'label' => 'Slug', + 'required' => false, + 'help' => 'Laisser vide pour une génération automatique', + 'attr' => [ + ], + 'constraints' => [ + ], + ] + ); + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => Category::class, + ]); + } +} diff --git a/src/Manager/EntityManager.php b/src/Manager/EntityManager.php index 19aba0d..a841dbd 100644 --- a/src/Manager/EntityManager.php +++ b/src/Manager/EntityManager.php @@ -2,7 +2,7 @@ namespace App\Manager; -use App\Entity\Entity; +use App\Entity\EntityInterface; use App\Event\EntityManager\EntityManagerEvent; use Doctrine\ORM\EntityManager as DoctrineEntityManager; use Doctrine\ORM\EntityManagerInterface; @@ -25,7 +25,7 @@ class EntityManager $this->entityManager = $entityManager; } - public function create(Entity $entity): self + public function create(EntityInterface $entity): self { $this->persist($entity); $this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::CREATE_EVENT); @@ -33,7 +33,7 @@ class EntityManager return $this; } - public function update(Entity $entity): self + public function update(EntityInterface $entity): self { $this->persist($entity); $this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::UPDATE_EVENT); @@ -41,9 +41,9 @@ class EntityManager return $this; } - public function delete(Entity $entity): self + public function delete(EntityInterface $entity): self { - $this->remove($entity); + $this->entityManager->remove($entity); $this->eventDispatcher->dispatch(new EntityManagerEvent($entity), EntityManagerEvent::DELETE_EVENT); return $this; @@ -63,7 +63,7 @@ class EntityManager return $this; } - protected function persist(Entity $entity) + protected function persist(EntityInterface $entity) { $this->entityManager->persist($entity); } diff --git a/src/Repository/Blog/CategoryRepositoryQuery.php b/src/Repository/Blog/CategoryRepositoryQuery.php index 2292122..2b86f71 100644 --- a/src/Repository/Blog/CategoryRepositoryQuery.php +++ b/src/Repository/Blog/CategoryRepositoryQuery.php @@ -2,9 +2,8 @@ namespace App\Repository\Blog; -use Knp\Component\Pager\PaginatorInterface; -use App\Repository\Blog\PostRepository; use App\Repository\RepositoryQuery; +use Knp\Component\Pager\PaginatorInterface; /** * class CategoryRepositoryQuery. diff --git a/src/Repository/Blog/PostRepositoryQuery.php b/src/Repository/Blog/PostRepositoryQuery.php index 4c386b5..4d45843 100644 --- a/src/Repository/Blog/PostRepositoryQuery.php +++ b/src/Repository/Blog/PostRepositoryQuery.php @@ -2,9 +2,9 @@ namespace App\Repository\Blog; -use Knp\Component\Pager\PaginatorInterface; -use App\Repository\Blog\PostRepository; +use App\Entity\Blog\Category; use App\Repository\RepositoryQuery; +use Knp\Component\Pager\PaginatorInterface; /** * class PostRepositoryQuery. @@ -17,4 +17,17 @@ class PostRepositoryQuery extends RepositoryQuery { parent::__construct($repository, 'p', $paginator); } + + public function inCategory(Category $category) + { + $c = 'c'.mt_rand(); + + $this + ->innerJoin('p.categories', $c) + ->andWhere($c.'.id = :category') + ->setParameter(':category', $category->getId()) + ; + + return $this; + } } diff --git a/src/Repository/RepositoryQuery.php b/src/Repository/RepositoryQuery.php index 88b1c8f..6324c32 100644 --- a/src/Repository/RepositoryQuery.php +++ b/src/Repository/RepositoryQuery.php @@ -2,7 +2,6 @@ namespace App\Repository; -use App\Criteria\CriteriaMap; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\ORM\QueryBuilder; use Knp\Component\Pager\PaginatorInterface; @@ -27,27 +26,20 @@ abstract class RepositoryQuery $this->id = $id; } - public function create() - { - $class = get_called_class(); - - return new $class($this->repository, $this->paginator); - } - public function __call(string $name, $params): self { - $fn = function(&$data) { + $fn = function (&$data) { if (is_string($data)) { $words = explode(' ', $data); foreach ($words as $k => $v) { - if (isset($v[0]) && $v[0] === '.') { + if (isset($v[0]) && '.' === $v[0]) { $words[$k] = $this->id.$v; } } $data = implode(' ', $words); - } else { + } elseif (is_array($data)) { foreach ($data as $k => $v) { $fn($data[$k]); } @@ -56,8 +48,7 @@ abstract class RepositoryQuery return $data; }; - foreach ($params as $key => $value) - { + foreach ($params as $key => $value) { $fn($params[$key]); } @@ -66,6 +57,13 @@ abstract class RepositoryQuery return $this; } + public function create() + { + $class = get_called_class(); + + return new $class($this->repository, $this->paginator); + } + public function call(callable $fn): self { $fn($this->query, $this); diff --git a/templates/admin/layout.html.twig b/templates/admin/layout.html.twig index bf82df5..d83e108 100644 --- a/templates/admin/layout.html.twig +++ b/templates/admin/layout.html.twig @@ -104,7 +104,7 @@ {% endblock %} {% block js %} - + {{ encore_entry_script_tags('admin') }} {% endblock %} diff --git a/templates/blog/category_admin/_form.html.twig b/templates/blog/category_admin/_form.html.twig new file mode 100644 index 0000000..b8d77b0 --- /dev/null +++ b/templates/blog/category_admin/_form.html.twig @@ -0,0 +1,17 @@ +
+
+
+ {% for item in ['title', 'subTitle', 'slug'] %} +
+ {{ form_row(form[item]) }} +
+ {% endfor %} +
+
+
+ {% for item in ['description'] %} + {{ form_row(form[item]) }} + {% endfor %} +
+
+ diff --git a/templates/blog/category_admin/edit.html.twig b/templates/blog/category_admin/edit.html.twig new file mode 100644 index 0000000..503b8ea --- /dev/null +++ b/templates/blog/category_admin/edit.html.twig @@ -0,0 +1,57 @@ +{% extends 'admin/layout.html.twig' %} + +{% block body %} +
+
+
+

{{ entity.title }}

+
+ +
+
+ + + Retour à la liste + + + + Voir + + + + + + +
+
+
+
+ +
+
+
+
+ {{ include('blog/category_admin/_form.html.twig') }} +
+
+
+ + {{ form_rest(form) }} +
+ +
+ + +
+{% endblock %} diff --git a/templates/blog/category_admin/index.html.twig b/templates/blog/category_admin/index.html.twig index fc8b6d0..27b9c49 100644 --- a/templates/blog/category_admin/index.html.twig +++ b/templates/blog/category_admin/index.html.twig @@ -1,16 +1,23 @@ {% extends 'admin/layout.html.twig' %} {% block body %} -
+

Catégories

- +
+ + {{ knp_pagination_render(pager) }}
@@ -20,28 +27,51 @@ - - - {% for item in range(1, 4) %} - - - - - - {% endfor %} + + + {% for item in pager %} + {% set edit = path('admin_blog_category_edit', {entity: item.id}) %} + {% set show = path('admin_blog_category_show', {entity: item.id}) %} + + + + + + + {% else %} + + + + {% endfor %}
Articles Actions
- Titre de la catégories
-
- - 5 articles - - - - -
+ + {{ item.title }} + + + + {% set postsCount = item.posts|length %} + + {{ postsCount }} {{ postsCount < 2 ? 'article' : 'articles' }} + + + + + + + +
+ + +
+
+
+ +
+
+ Aucun résultat +
+
{% endblock %} diff --git a/templates/blog/category_admin/new.html.twig b/templates/blog/category_admin/new.html.twig new file mode 100644 index 0000000..c8eb21b --- /dev/null +++ b/templates/blog/category_admin/new.html.twig @@ -0,0 +1,39 @@ +{% extends 'admin/layout.html.twig' %} + +{% block body %} +
+
+
+

Nouvelle catégorie

+
+ +
+
+ + + + Retour à la liste + + + +
+
+
+
+ +
+
+
+
+ {{ include('blog/category_admin/_form.html.twig') }} +
+
+
+ + {{ form_rest(form) }} +
+{% endblock %} diff --git a/templates/blog/category_admin/show.html.twig b/templates/blog/category_admin/show.html.twig new file mode 100644 index 0000000..c7e3779 --- /dev/null +++ b/templates/blog/category_admin/show.html.twig @@ -0,0 +1,83 @@ +{% extends 'admin/layout.html.twig' %} + +{% block body %} +
+
+
+

{{ entity.title }}

+
+ + +
+
+ +
+
+
    +
  • + Titre
    + + {{ entity.title }} +
  • +
  • + Sous-titre
    + + {{ entity.subTitle }} +
  • +
  • + URL
    + + {{ absolute_url('/' ~ entity.slug) }} +
  • +
+
+
+
Description
+ + {{ entity.description|raw|nl2br }} +
+ +
+ + + + + + + + {% for item in posts %} + + + + {% else %} + + + + {% endfor %} + +
Derniers articles
+ {{ item.post }} +
+
+ +
+
+ Aucun résultat +
+
+
+
+{% endblock %} diff --git a/yarn.lock b/yarn.lock index 714d8a3..188c1d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5771,10 +5771,10 @@ timsort@^0.3.0: resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= -tinymce@^5.2.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-5.7.0.tgz#bc565877e4041db83848a330dfa7916993110cba" - integrity sha512-WikgMpJbqYPaucV3lfstCj+Y4NquZlK61gyuJ2eqDUBlSU+4fFh6rpwnelVTxuvtEyJsAVOl8HZmbzBfDJiLsQ== +tinymce@^5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-5.7.1.tgz#658a6fb4c7d53a8496cc00f8da33f4b8290da06d" + integrity sha512-1gY8RClc734srSlkYwY0MQzmkS1j73PuPC+nYtNtrrQVPY9VNcZ4bOiRwzTbdjPPD8GOtv6BAk8Ww/H2RiqKpA== tmp@^0.2.1: version "0.2.1"