diff --git a/app/Resources/static/themes/material/css/cards.scss b/app/Resources/static/themes/material/css/cards.scss index 830897b24..0330da5d9 100644 --- a/app/Resources/static/themes/material/css/cards.scss +++ b/app/Resources/static/themes/material/css/cards.scss @@ -177,6 +177,7 @@ a.original:not(.waves-effect) { .card-entry-tags a, .card-entry-labels a, .card-tag-labels a, +.card-tag-labels button, .card-entry-labels-hidden a, #list .chip a { text-decoration: none; diff --git a/app/Resources/static/themes/material/css/dark_theme.scss b/app/Resources/static/themes/material/css/dark_theme.scss index ac38b566d..532442360 100644 --- a/app/Resources/static/themes/material/css/dark_theme.scss +++ b/app/Resources/static/themes/material/css/dark_theme.scss @@ -62,7 +62,9 @@ .nav-panels .input-field input:focus, .results-item, .side-nav li > a, - .side-nav li > a > i.material-icons { + .side-nav li > a > i.material-icons, + .side-nav li button, + .side-nav li button > i.material-icons { color: #dfdfdf; } @@ -87,6 +89,7 @@ .mass-action-tags .mass-action-tags-input.mass-action-tags-input, .side-nav li:not(.logo) > a:hover, + .side-nav li:not(.logo) button:hover, .side-nav .collapsible-header:hover, .side-nav.fixed .collapsible-header:hover { background-color: #1d1d1d; diff --git a/app/Resources/static/themes/material/css/nav.scss b/app/Resources/static/themes/material/css/nav.scss index a085febd9..8a83596ff 100644 --- a/app/Resources/static/themes/material/css/nav.scss +++ b/app/Resources/static/themes/material/css/nav.scss @@ -6,11 +6,32 @@ nav { line-height: initial; } +// adapted from anchor styles from node_modules/materialize-css/sass/components/_navbar.scss +nav ul button { + transition: background-color .3s; + font-size: 1rem; + color: #fff; + display: block; + padding: 0 15px; + cursor: pointer; + background: none; + border: 0; + + &:focus { + background: none; + } + + &:hover { + background-color: rgba(0 0 0 / 10%); + } +} + nav { input { color: #aaa; } + ul button:hover, ul a:hover { background-color: initial; } @@ -34,6 +55,7 @@ nav { justify-content: space-between; align-items: center; + button, a { padding: 10px 15px; } diff --git a/app/Resources/static/themes/material/css/sidenav.scss b/app/Resources/static/themes/material/css/sidenav.scss index 00e4c5c2a..a7e50851e 100644 --- a/app/Resources/static/themes/material/css/sidenav.scss +++ b/app/Resources/static/themes/material/css/sidenav.scss @@ -12,6 +12,7 @@ background: initial; } + & button > i.material-icons.theme-toggle-icon, & > a > i.material-icons.theme-toggle-icon { float: none; margin-left: 0; @@ -22,6 +23,7 @@ margin: 0; } + &.fixed button, &.fixed a { font-size: 13px; line-height: 44px; @@ -41,7 +43,35 @@ } } -.bold > a { +// adapted from anchor styles from node_modules/materialize-css/sass/components/_sideNav.scss +.side-nav li button { + color: rgba(0 0 0 / 87%); + display: block; + font-size: 14px; + font-weight: 500; + height: 48px; + line-height: 48px; + padding: 0 (16px * 2); + width: 100%; + text-align: left; + + &:hover { + background-color: rgba(0 0 0 / 5%); + } + + & > i, + & > i.material-icons { + float: left; + height: 48px; + line-height: 48px; + margin: 0 (16px * 2) 0 0; + width: 24px; + color: rgba(0 0 0 / 54%); + } +} + +.bold > a, +.bold > button { font-weight: bold; } diff --git a/app/Resources/static/themes/material/css/various.scss b/app/Resources/static/themes/material/css/various.scss index ad0703afa..94bb95bd0 100644 --- a/app/Resources/static/themes/material/css/various.scss +++ b/app/Resources/static/themes/material/css/various.scss @@ -38,3 +38,18 @@ nav .input-field input { .tab { flex: 1; } + +.btn-link { + background: none; + border: 0; + padding: 0; + color: $blue-accent-color; + + &:focus { + background: none; + } +} + +.inline-block { + display: inline-block; +} diff --git a/app/Resources/static/themes/material/index.js b/app/Resources/static/themes/material/index.js index 704a9ea11..24adf8aab 100755 --- a/app/Resources/static/themes/material/index.js +++ b/app/Resources/static/themes/material/index.js @@ -228,10 +228,10 @@ $(document).ready(() => { }); }); } - $('form[name="form_mass_action"] input[name="tags"]').on('keydown', (e) => { + $('input[name="tags"][form="form_mass_action"]').on('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); - $('form[name="form_mass_action"] button[name="tag"]').trigger('click'); + $('button[name="tag"][form="form_mass_action"]').trigger('click'); } }); }); diff --git a/app/Resources/static/themes/material/js/shortcuts/entry.js b/app/Resources/static/themes/material/js/shortcuts/entry.js index e19800bd3..1c916b200 100644 --- a/app/Resources/static/themes/material/js/shortcuts/entry.js +++ b/app/Resources/static/themes/material/js/shortcuts/entry.js @@ -10,17 +10,17 @@ $(document).ready(() => { /* mark as favorite */ Mousetrap.bind('f', () => { - $('ul.side-nav a.favorite i')[0].click(); + $('ul.side-nav button.favorite i')[0].click(); }); /* mark as read */ Mousetrap.bind('a', () => { - $('ul.side-nav a.markasread i')[0].click(); + $('ul.side-nav button.markasread i')[0].click(); }); /* delete */ Mousetrap.bind('del', () => { - $('ul.side-nav a.delete i')[0].click(); + $('ul.side-nav button.delete i')[0].click(); }); } }); diff --git a/app/config/config.yml b/app/config/config.yml index 064df3623..cd981163d 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -30,6 +30,7 @@ framework: handler_id: session.handler.native_file save_path: "%kernel.project_dir%/var/sessions/%kernel.environment%" cookie_secure: auto + cookie_samesite: lax fragments: ~ http_method_override: true assets: ~ diff --git a/src/Wallabag/ApiBundle/Controller/DeveloperController.php b/src/Wallabag/ApiBundle/Controller/DeveloperController.php index 0c08968e2..5b2d6accc 100644 --- a/src/Wallabag/ApiBundle/Controller/DeveloperController.php +++ b/src/Wallabag/ApiBundle/Controller/DeveloperController.php @@ -7,6 +7,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Annotation\Route; use Symfony\Contracts\Translation\TranslatorInterface; use Wallabag\ApiBundle\Entity\Client; @@ -76,7 +77,7 @@ class DeveloperController extends AbstractController public function deleteClientAction(Request $request, Client $client, EntityManagerInterface $entityManager, TranslatorInterface $translator) { if (!$this->isCsrfTokenValid('delete-client', $request->request->get('token'))) { - throw $this->createAccessDeniedException('Bad CSRF token.'); + throw new BadRequestHttpException('Bad CSRF token.'); } if (null === $this->getUser() || $client->getUser()->getId() !== $this->getUser()->getId()) { diff --git a/src/Wallabag/CoreBundle/Controller/ConfigController.php b/src/Wallabag/CoreBundle/Controller/ConfigController.php index 4709a4d2e..1ba7faaed 100644 --- a/src/Wallabag/CoreBundle/Controller/ConfigController.php +++ b/src/Wallabag/CoreBundle/Controller/ConfigController.php @@ -16,6 +16,7 @@ use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Validator\Constraints\Locale as LocaleConstraint; @@ -262,7 +263,7 @@ class ConfigController extends AbstractController public function disableOtpEmailAction(Request $request) { if (!$this->isCsrfTokenValid('otp', $request->request->get('token'))) { - throw $this->createAccessDeniedException('Bad CSRF token.'); + throw new BadRequestHttpException('Bad CSRF token.'); } $user = $this->getUser(); @@ -286,7 +287,7 @@ class ConfigController extends AbstractController public function otpEmailAction(Request $request) { if (!$this->isCsrfTokenValid('otp', $request->request->get('token'))) { - throw $this->createAccessDeniedException('Bad CSRF token.'); + throw new BadRequestHttpException('Bad CSRF token.'); } $user = $this->getUser(); @@ -313,7 +314,7 @@ class ConfigController extends AbstractController public function disableOtpAppAction(Request $request) { if (!$this->isCsrfTokenValid('otp', $request->request->get('token'))) { - throw $this->createAccessDeniedException('Bad CSRF token.'); + throw new BadRequestHttpException('Bad CSRF token.'); } $user = $this->getUser(); @@ -339,7 +340,7 @@ class ConfigController extends AbstractController public function otpAppAction(Request $request, GoogleAuthenticatorInterface $googleAuthenticator) { if (!$this->isCsrfTokenValid('otp', $request->request->get('token'))) { - throw $this->createAccessDeniedException('Bad CSRF token.'); + throw new BadRequestHttpException('Bad CSRF token.'); } $user = $this->getUser(); @@ -398,7 +399,7 @@ class ConfigController extends AbstractController public function otpAppCheckAction(Request $request, GoogleAuthenticatorInterface $googleAuthenticator) { if (!$this->isCsrfTokenValid('otp', $request->request->get('token'))) { - throw $this->createAccessDeniedException('Bad CSRF token.'); + throw new BadRequestHttpException('Bad CSRF token.'); } $isValid = $googleAuthenticator->checkCode( @@ -429,22 +430,22 @@ class ConfigController extends AbstractController } /** - * @Route("/generate-token", name="generate_token") + * @Route("/generate-token", name="generate_token", methods={"POST"}) * * @return RedirectResponse|JsonResponse */ public function generateTokenAction(Request $request) { + if (!$this->isCsrfTokenValid('generate-token', $request->request->get('token'))) { + throw new BadRequestHttpException('Bad CSRF token.'); + } + $config = $this->getConfig(); $config->setFeedToken(Utils::generateToken()); $this->entityManager->persist($config); $this->entityManager->flush(); - if ($request->isXmlHttpRequest()) { - return new JsonResponse(['token' => $config->getFeedToken()]); - } - $this->addFlash( 'notice', 'flashes.config.notice.feed_token_updated' @@ -454,22 +455,22 @@ class ConfigController extends AbstractController } /** - * @Route("/revoke-token", name="revoke_token") + * @Route("/revoke-token", name="revoke_token", methods={"POST"}) * * @return RedirectResponse|JsonResponse */ public function revokeTokenAction(Request $request) { + if (!$this->isCsrfTokenValid('revoke-token', $request->request->get('token'))) { + throw new BadRequestHttpException('Bad CSRF token.'); + } + $config = $this->getConfig(); $config->setFeedToken(null); $this->entityManager->persist($config); $this->entityManager->flush(); - if ($request->isXmlHttpRequest()) { - return new JsonResponse(); - } - $this->addFlash( 'notice', 'flashes.config.notice.feed_token_revoked' @@ -481,12 +482,16 @@ class ConfigController extends AbstractController /** * Deletes a tagging rule and redirect to the config homepage. * - * @Route("/tagging-rule/delete/{id}", requirements={"id" = "\d+"}, name="delete_tagging_rule") + * @Route("/tagging-rule/delete/{id}", name="delete_tagging_rule", methods={"POST"}, requirements={"id" = "\d+"}) * * @return RedirectResponse */ - public function deleteTaggingRuleAction(TaggingRule $rule) + public function deleteTaggingRuleAction(Request $request, TaggingRule $rule) { + if (!$this->isCsrfTokenValid('delete-tagging-rule', $request->request->get('token'))) { + throw new BadRequestHttpException('Bad CSRF token.'); + } + $this->validateRuleAction($rule); $this->entityManager->remove($rule); @@ -517,12 +522,16 @@ class ConfigController extends AbstractController /** * Deletes an ignore origin rule and redirect to the config homepage. * - * @Route("/ignore-origin-user-rule/delete/{id}", requirements={"id" = "\d+"}, name="delete_ignore_origin_rule") + * @Route("/ignore-origin-user-rule/delete/{id}", name="delete_ignore_origin_rule", methods={"POST"}, requirements={"id" = "\d+"}) * * @return RedirectResponse */ - public function deleteIgnoreOriginRuleAction(IgnoreOriginUserRule $rule) + public function deleteIgnoreOriginRuleAction(Request $request, IgnoreOriginUserRule $rule) { + if (!$this->isCsrfTokenValid('delete-ignore-origin-rule', $request->request->get('token'))) { + throw new BadRequestHttpException('Bad CSRF token.'); + } + $this->validateRuleAction($rule); $this->entityManager->remove($rule); @@ -560,7 +569,7 @@ class ConfigController extends AbstractController public function resetAction(Request $request, string $type, AnnotationRepository $annotationRepository, EntryRepository $entryRepository) { if (!$this->isCsrfTokenValid('reset-area', $request->request->get('token'))) { - throw $this->createAccessDeniedException('Bad CSRF token.'); + throw new BadRequestHttpException('Bad CSRF token.'); } switch ($type) { @@ -614,7 +623,7 @@ class ConfigController extends AbstractController public function deleteAccountAction(Request $request, UserRepository $userRepository, TokenStorageInterface $tokenStorage) { if (!$this->isCsrfTokenValid('delete-account', $request->request->get('token'))) { - throw $this->createAccessDeniedException('Bad CSRF token.'); + throw new BadRequestHttpException('Bad CSRF token.'); } $enabledUsers = $userRepository->getSumEnabledUsers(); @@ -637,12 +646,16 @@ class ConfigController extends AbstractController /** * Switch view mode for current user. * - * @Route("/config/view-mode", name="switch_view_mode") + * @Route("/config/view-mode", name="switch_view_mode", methods={"POST"}) * * @return RedirectResponse */ public function changeViewModeAction(Request $request) { + if (!$this->isCsrfTokenValid('switch-view-mode', $request->request->get('token'))) { + throw new BadRequestHttpException('Bad CSRF token.'); + } + $user = $this->getUser(); $user->getConfig()->setListMode(!$user->getConfig()->getListMode()); @@ -659,12 +672,16 @@ class ConfigController extends AbstractController * * @param string $language * - * @Route("/locale/{language}", name="changeLocale") + * @Route("/locale/{language}", name="changeLocale", methods={"POST"}) * * @return RedirectResponse */ public function setLocaleAction(Request $request, ValidatorInterface $validator, $language = null) { + if (!$this->isCsrfTokenValid('change-locale', $request->request->get('token'))) { + throw new BadRequestHttpException('Bad CSRF token.'); + } + $errors = $validator->validate($language, (new LocaleConstraint())); if (0 === \count($errors)) { diff --git a/src/Wallabag/CoreBundle/Controller/EntryController.php b/src/Wallabag/CoreBundle/Controller/EntryController.php index 3b624dd1f..be862d750 100644 --- a/src/Wallabag/CoreBundle/Controller/EntryController.php +++ b/src/Wallabag/CoreBundle/Controller/EntryController.php @@ -14,6 +14,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Annotation\Route; use Symfony\Contracts\Translation\TranslatorInterface; use Wallabag\CoreBundle\Entity\Entry; @@ -52,12 +53,16 @@ class EntryController extends AbstractController } /** - * @Route("/mass", name="mass_action") + * @Route("/mass", name="mass_action", methods={"POST"}) * * @return Response */ public function massAction(Request $request, TagRepository $tagRepository) { + if (!$this->isCsrfTokenValid('mass-action', $request->request->get('token'))) { + throw new BadRequestHttpException('Bad CSRF token.'); + } + $values = $request->request->all(); $tagsToAdd = []; @@ -400,12 +405,16 @@ class EntryController extends AbstractController * Reload an entry. * Refetch content from the website and make it readable again. * - * @Route("/reload/{id}", requirements={"id" = "\d+"}, name="reload_entry") + * @Route("/reload/{id}", name="reload_entry", methods={"POST"}, requirements={"id" = "\d+"}) * * @return RedirectResponse */ - public function reloadAction(Entry $entry) + public function reloadAction(Request $request, Entry $entry) { + if (!$this->isCsrfTokenValid('reload-entry', $request->request->get('token'))) { + throw new BadRequestHttpException('Bad CSRF token.'); + } + $this->checkUserAction($entry); $this->updateEntry($entry, 'entry_reloaded'); @@ -429,12 +438,16 @@ class EntryController extends AbstractController /** * Changes read status for an entry. * - * @Route("/archive/{id}", requirements={"id" = "\d+"}, name="archive_entry") + * @Route("/archive/{id}", name="archive_entry", methods={"POST"}, requirements={"id" = "\d+"}) * * @return RedirectResponse */ public function toggleArchiveAction(Request $request, Entry $entry) { + if (!$this->isCsrfTokenValid('archive-entry', $request->request->get('token'))) { + throw new BadRequestHttpException('Bad CSRF token.'); + } + $this->checkUserAction($entry); $entry->toggleArchive(); @@ -458,12 +471,16 @@ class EntryController extends AbstractController /** * Changes starred status for an entry. * - * @Route("/star/{id}", requirements={"id" = "\d+"}, name="star_entry") + * @Route("/star/{id}", name="star_entry", methods={"POST"}, requirements={"id" = "\d+"}) * * @return RedirectResponse */ public function toggleStarAction(Request $request, Entry $entry) { + if (!$this->isCsrfTokenValid('star-entry', $request->request->get('token'))) { + throw new BadRequestHttpException('Bad CSRF token.'); + } + $this->checkUserAction($entry); $entry->toggleStar(); @@ -488,12 +505,16 @@ class EntryController extends AbstractController /** * Deletes entry and redirect to the homepage or the last viewed page. * - * @Route("/delete/{id}", requirements={"id" = "\d+"}, name="delete_entry") + * @Route("/delete/{id}", name="delete_entry", methods={"POST"}, requirements={"id" = "\d+"}) * * @return RedirectResponse */ public function deleteEntryAction(Request $request, Entry $entry) { + if (!$this->isCsrfTokenValid('delete-entry', $request->request->get('token'))) { + throw new BadRequestHttpException('Bad CSRF token.'); + } + $this->checkUserAction($entry); // generates the view url for this entry to check for redirection later @@ -526,12 +547,16 @@ class EntryController extends AbstractController /** * Get public URL for entry (and generate it if necessary). * - * @Route("/share/{id}", requirements={"id" = "\d+"}, name="share") + * @Route("/share/{id}", name="share", methods={"POST"}, requirements={"id" = "\d+"}) * * @return Response */ - public function shareAction(Entry $entry) + public function shareAction(Request $request, Entry $entry) { + if (!$this->isCsrfTokenValid('share-entry', $request->request->get('token'))) { + throw new BadRequestHttpException('Bad CSRF token.'); + } + $this->checkUserAction($entry); if (null === $entry->getUid()) { @@ -549,12 +574,16 @@ class EntryController extends AbstractController /** * Disable public sharing for an entry. * - * @Route("/share/delete/{id}", requirements={"id" = "\d+"}, name="delete_share") + * @Route("/share/delete/{id}", name="delete_share", methods={"POST"}, requirements={"id" = "\d+"}) * * @return Response */ - public function deleteShareAction(Entry $entry) + public function deleteShareAction(Request $request, Entry $entry) { + if (!$this->isCsrfTokenValid('delete-share', $request->request->get('token'))) { + throw new BadRequestHttpException('Bad CSRF token.'); + } + $this->checkUserAction($entry); $entry->cleanUid(); @@ -570,7 +599,7 @@ class EntryController extends AbstractController /** * Ability to view a content publicly. * - * @Route("/share/{uid}", requirements={"uid" = ".+"}, name="share_entry") + * @Route("/share/{uid}", name="share_entry", methods={"GET"}, requirements={"uid" = ".+"}) * @Cache(maxage="25200", smaxage="25200", public=true) * * @return Response diff --git a/src/Wallabag/CoreBundle/Controller/TagController.php b/src/Wallabag/CoreBundle/Controller/TagController.php index 804512563..9b7a189bf 100644 --- a/src/Wallabag/CoreBundle/Controller/TagController.php +++ b/src/Wallabag/CoreBundle/Controller/TagController.php @@ -10,6 +10,7 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Routing\Annotation\Route; use Symfony\Contracts\Translation\TranslatorInterface; use Wallabag\CoreBundle\Entity\Entry; @@ -87,12 +88,16 @@ class TagController extends AbstractController /** * Removes tag from entry. * - * @Route("/remove-tag/{entry}/{tag}", requirements={"entry" = "\d+", "tag" = "\d+"}, name="remove_tag") + * @Route("/remove-tag/{entry}/{tag}", name="remove_tag", methods={"POST"}, requirements={"entry" = "\d+", "tag" = "\d+"}) * * @return Response */ public function removeTagFromEntry(Request $request, Entry $entry, Tag $tag) { + if (!$this->isCsrfTokenValid('remove-tag', $request->request->get('token'))) { + throw new BadRequestHttpException('Bad CSRF token.'); + } + $this->checkUserAction($entry); $entry->removeTag($tag); @@ -228,12 +233,16 @@ class TagController extends AbstractController /** * Tag search results with the current search term. * - * @Route("/tag/search/{filter}", name="tag_this_search") + * @Route("/tag/search/{filter}", name="tag_this_search", methods={"POST"}) * * @return Response */ public function tagThisSearchAction($filter, Request $request, EntryRepository $entryRepository) { + if (!$this->isCsrfTokenValid('tag-this-search', $request->request->get('token'))) { + throw new BadRequestHttpException('Bad CSRF token.'); + } + $currentRoute = $request->query->has('currentRoute') ? $request->query->get('currentRoute') : ''; /** @var QueryBuilder $qb */ @@ -263,13 +272,17 @@ class TagController extends AbstractController /** * Delete a given tag for the current user. * - * @Route("/tag/delete/{slug}", name="tag_delete") + * @Route("/tag/delete/{slug}", name="tag_delete", methods={"POST"}) * @ParamConverter("tag", options={"mapping": {"slug": "slug"}}) * * @return Response */ public function removeTagAction(Tag $tag, Request $request, EntryRepository $entryRepository) { + if (!$this->isCsrfTokenValid('tag-delete', $request->request->get('token'))) { + throw new BadRequestHttpException('Bad CSRF token.'); + } + foreach ($tag->getEntriesByUserId($this->getUser()->getId()) as $entry) { $entryRepository->removeTag($this->getUser()->getId(), $tag); } diff --git a/src/Wallabag/CoreBundle/Resources/views/Config/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/Config/index.html.twig index d52aa4c51..59031054d 100644 --- a/src/Wallabag/CoreBundle/Resources/views/Config/index.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/Config/index.html.twig @@ -123,48 +123,63 @@
+
+
+ {{ 'config.form_feed.description'|trans }} +
+
+ +
+
+
{{ 'config.form_feed.token_label'|trans }}
+
+ {% if feed.token %} + {{ feed.token }} + {% else %} + {{ 'config.form_feed.no_token'|trans }} + {% endif %} + + {% if feed.token %} + – +
+ + + +
+ – +
+ + + +
+ {% else %} + – +
+ + + +
+ {% endif %} +
+
+
+ {% if feed.token %} +
+ +
+ {% endif %} + {{ form_start(form.feed) }} {{ form_errors(form.feed) }} -
-
- {{ 'config.form_feed.description'|trans }} -
-
- -
-
-
{{ 'config.form_feed.token_label'|trans }}
-
- {% if feed.token %} - {{ feed.token }} - {% else %} - {{ 'config.form_feed.no_token'|trans }} - {% endif %} - - {% if feed.token %} - – {{ 'config.form_feed.token_reset'|trans }} - – {{ 'config.form_feed.token_revoke'|trans }} - {% else %} - – {{ 'config.form_feed.token_create'|trans }} - {% endif %} -
-
-
- {% if feed.token %} -
- -
- {% endif %} -
{{ form_label(form.feed.feed_limit) }} @@ -325,9 +340,13 @@ mode_edit - - delete - +
+ + + +
{% endfor %} @@ -505,9 +524,13 @@ mode_edit - - delete - +
+ + + +
{% endfor %} diff --git a/src/Wallabag/CoreBundle/Resources/views/Entry/Card/_mass_checkbox.html.twig b/src/Wallabag/CoreBundle/Resources/views/Entry/Card/_mass_checkbox.html.twig index 5e4fe8f6d..b4bd1e94b 100644 --- a/src/Wallabag/CoreBundle/Resources/views/Entry/Card/_mass_checkbox.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/Entry/Card/_mass_checkbox.html.twig @@ -1,3 +1,3 @@ diff --git a/src/Wallabag/CoreBundle/Resources/views/Entry/_card_actions.html.twig b/src/Wallabag/CoreBundle/Resources/views/Entry/_card_actions.html.twig index 8102409ee..140c283df 100644 --- a/src/Wallabag/CoreBundle/Resources/views/Entry/_card_actions.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/Entry/_card_actions.html.twig @@ -14,13 +14,31 @@ language
  • - {% if entry.isArchived == 0 %}done{% else %}unarchive{% endif %} +
    + + + +
  • - {% if entry.isStarred == 0 %}star_border{% else %}star{% endif %} +
    + + + +
  • - delete +
    + + + +
  • diff --git a/src/Wallabag/CoreBundle/Resources/views/Entry/_card_list.html.twig b/src/Wallabag/CoreBundle/Resources/views/Entry/_card_list.html.twig index 78b918912..41877a0f5 100644 --- a/src/Wallabag/CoreBundle/Resources/views/Entry/_card_list.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/Entry/_card_list.html.twig @@ -15,9 +15,27 @@
    diff --git a/src/Wallabag/CoreBundle/Resources/views/Entry/_tags.html.twig b/src/Wallabag/CoreBundle/Resources/views/Entry/_tags.html.twig index 2ab67e1c8..9a7db546f 100644 --- a/src/Wallabag/CoreBundle/Resources/views/Entry/_tags.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/Entry/_tags.html.twig @@ -5,9 +5,13 @@ {{ tag.label }} {% if withRemove is defined and withRemove == true %} {% set current_path = path(app.request.attributes.get('_route'), app.request.attributes.get('_route_params')) %} - - delete - +
    + + + +
    {% endif %} {% endfor %} diff --git a/src/Wallabag/CoreBundle/Resources/views/Entry/entries.html.twig b/src/Wallabag/CoreBundle/Resources/views/Entry/entries.html.twig index 2c26b24af..a02094d42 100644 --- a/src/Wallabag/CoreBundle/Resources/views/Entry/entries.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/Entry/entries.html.twig @@ -26,12 +26,20 @@ {% if current_route == 'homepage' %} {% set current_route = 'unread' %} {% endif %} -
    + + +
    {{ 'entry.list.number_on_the_page'|trans({'%count%': entries.count}) }} {% if entries.count > 0 %} - {% if list_mode == 0 %}view_list{% else %}view_module{% endif %} +
    + + + +
    {% endif %} {% if entries.count > 0 %} @@ -40,7 +48,13 @@ {% include "@WallabagCore/Entry/_feed_link.html.twig" %} {% endif %}
    - {% if current_route == 'search' %}
    {{ 'entry.list.assign_search_tag'|trans }}
    {% endif %} + {% if current_route == 'search' %} +
    + + + +
    + {% endif %} {% if entries.getNbPages > 1 %} {{ pagerfanta(entries, 'default_wallabag') }} {% endif %} @@ -50,15 +64,15 @@
    - - - - + + + +
    - - + +
    @@ -77,7 +91,6 @@ {% endfor %} {% endif %} - {% if entries.getNbPages > 1 %}
    diff --git a/src/Wallabag/CoreBundle/Resources/views/Entry/entry.html.twig b/src/Wallabag/CoreBundle/Resources/views/Entry/entry.html.twig index 9ce783bbf..505f60eba 100644 --- a/src/Wallabag/CoreBundle/Resources/views/Entry/entry.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/Entry/entry.html.twig @@ -26,14 +26,22 @@
    @@ -56,10 +64,14 @@
  • - - refresh - {{ 'entry.view.left_menu.re_fetch_content'|trans }} - +
    + + + +
  • @@ -69,25 +81,37 @@ {% endif %}
  • - - {% if entry.isArchived == 0 %}done{% else %}unarchive{% endif %} - {{ mark_as_read_label|trans }} - +
    + + + +
  • - - {% if entry.isStarred == 0 %}star_outline{% else %}star{% endif %} - {{ 'entry.view.left_menu.set_as_starred'|trans }} - +
    + + + +
  • - - delete - {{ 'entry.view.left_menu.delete'|trans }} - +
    + + + +
  • @@ -135,14 +159,22 @@
    diff --git a/src/Wallabag/CoreBundle/Resources/views/Tag/tags.html.twig b/src/Wallabag/CoreBundle/Resources/views/Tag/tags.html.twig index bff22436e..361947762 100644 --- a/src/Wallabag/CoreBundle/Resources/views/Tag/tags.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/Tag/tags.html.twig @@ -28,9 +28,13 @@ mode_edit {% endif %} - - delete - +
    + + + +
    {% if app.user.config.feedToken %} rss_feed {% endif %} diff --git a/templates/bundles/FOSUserBundle/layout.html.twig b/templates/bundles/FOSUserBundle/layout.html.twig index 937fd5cb0..191b492e5 100644 --- a/templates/bundles/FOSUserBundle/layout.html.twig +++ b/templates/bundles/FOSUserBundle/layout.html.twig @@ -16,9 +16,23 @@ {% endblock fos_user_content %}
    - Deutsch – - English – - Français +
    + + + +
    + – +
    + + + +
    + – +
    + + + +
    diff --git a/tests/Wallabag/ApiBundle/Controller/DeveloperControllerTest.php b/tests/Wallabag/ApiBundle/Controller/DeveloperControllerTest.php index 35573809a..31218a057 100644 --- a/tests/Wallabag/ApiBundle/Controller/DeveloperControllerTest.php +++ b/tests/Wallabag/ApiBundle/Controller/DeveloperControllerTest.php @@ -105,7 +105,7 @@ class DeveloperControllerTest extends WallabagCoreTestCase $this->logInAs('bob'); $client->request('POST', '/developer/client/delete/' . $adminApiClient->getId()); - $this->assertSame(403, $client->getResponse()->getStatusCode()); + $this->assertSame(400, $client->getResponse()->getStatusCode()); // Try to remove the admin's client with the good user $this->logInAs('admin'); diff --git a/tests/Wallabag/CoreBundle/Controller/ConfigControllerTest.php b/tests/Wallabag/CoreBundle/Controller/ConfigControllerTest.php index 6c049e1dc..c4bcf6194 100644 --- a/tests/Wallabag/CoreBundle/Controller/ConfigControllerTest.php +++ b/tests/Wallabag/CoreBundle/Controller/ConfigControllerTest.php @@ -328,7 +328,8 @@ class ConfigControllerTest extends WallabagCoreTestCase $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text'])); $this->assertStringContainsString('config.form_feed.no_token', $body[0]); - $client->request('GET', '/generate-token'); + $client->submit($crawler->selectButton('config.form_feed.token_create')->form()); + $this->assertSame(302, $client->getResponse()->getStatusCode()); $crawler = $client->followRedirect(); @@ -337,38 +338,34 @@ class ConfigControllerTest extends WallabagCoreTestCase $this->assertStringContainsString('config.form_feed.token_reset', $body[0]); } - public function testGenerateTokenAjax() - { - $this->logInAs('admin'); - $client = $this->getTestClient(); - - $client->request( - 'GET', - '/generate-token', - [], - [], - ['HTTP_X-Requested-With' => 'XMLHttpRequest'] - ); - - $this->assertSame(200, $client->getResponse()->getStatusCode()); - $content = json_decode($client->getResponse()->getContent(), true); - $this->assertArrayHasKey('token', $content); - } - public function testRevokeTokenAjax() { $this->logInAs('admin'); $client = $this->getTestClient(); - $client->request( - 'GET', - '/revoke-token', - [], - [], - ['HTTP_X-Requested-With' => 'XMLHttpRequest'] - ); + // set the token + $em = $client->getContainer()->get(EntityManagerInterface::class); + $user = $em + ->getRepository(User::class) + ->findOneByUsername('admin'); - $this->assertSame(200, $client->getResponse()->getStatusCode()); + if (!$user) { + $this->markTestSkipped('No user found in db.'); + } + + $config = $user->getConfig(); + $config->setFeedToken('abcd1234'); + $em->persist($config); + $em->flush(); + + $crawler = $client->request('GET', '/config'); + + $client->submit($crawler->selectButton('config.form_feed.token_revoke')->form()); + + $crawler = $client->followRedirect(); + + $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text'])); + $this->assertStringContainsString('config.form_feed.token_create', $body[0]); } public function testFeedUpdate() @@ -484,9 +481,8 @@ class ConfigControllerTest extends WallabagCoreTestCase $this->assertStringContainsString('readingTime <= 30', $crawler->filter('body')->extract(['_text'])[0]); - $deleteLink = $crawler->filter('.delete_tagging_rule')->last()->link(); + $crawler = $client->submit($crawler->filter('#set5')->selectButton('delete')->form()); - $crawler = $client->click($deleteLink); $this->assertSame(302, $client->getResponse()->getStatusCode()); $crawler = $client->followRedirect(); @@ -576,11 +572,11 @@ class ConfigControllerTest extends WallabagCoreTestCase ->getRepository(TaggingRule::class) ->findAll()[0]; - $crawler = $client->request('GET', '/tagging-rule/delete/' . $rule->getId()); + $crawler = $client->request('POST', '/tagging-rule/delete/' . $rule->getId()); - $this->assertSame(403, $client->getResponse()->getStatusCode()); + $this->assertSame(400, $client->getResponse()->getStatusCode()); $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text'])); - $this->assertStringContainsString('You can not access this rule', $body[0]); + $this->assertStringContainsString('Bad CSRF token.', $body[0]); } public function testEditingTaggingRuleFromAnOtherUser() @@ -646,9 +642,9 @@ class ConfigControllerTest extends WallabagCoreTestCase $this->assertStringContainsString('host = "example.org"', $crawler->filter('body')->extract(['_text'])[0]); - $deleteLink = $crawler->filter('div[id=set6] a.delete')->last()->link(); + $form = $crawler->filter('#set6')->selectButton('delete')->form(); - $crawler = $client->click($deleteLink); + $crawler = $client->submit($form); $this->assertSame(302, $client->getResponse()->getStatusCode()); $crawler = $client->followRedirect(); @@ -713,11 +709,11 @@ class ConfigControllerTest extends WallabagCoreTestCase ->getRepository(IgnoreOriginUserRule::class) ->findAll()[0]; - $crawler = $client->request('GET', '/ignore-origin-user-rule/edit/' . $rule->getId()); + $crawler = $client->request('POST', '/ignore-origin-user-rule/delete/' . $rule->getId()); - $this->assertSame(403, $client->getResponse()->getStatusCode()); + $this->assertSame(400, $client->getResponse()->getStatusCode()); $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text'])); - $this->assertStringContainsString('You can not access this rule', $body[0]); + $this->assertStringContainsString('Bad CSRF token.', $body[0]); } public function testEditingIgnoreOriginRuleFromAnOtherUser() @@ -798,7 +794,7 @@ class ConfigControllerTest extends WallabagCoreTestCase $this->assertStringNotContainsString('config.form_user.delete.button', $body[0]); $client->request('POST', '/account/delete'); - $this->assertSame(403, $client->getResponse()->getStatusCode()); + $this->assertSame(400, $client->getResponse()->getStatusCode()); $user = $em ->getRepository(User::class) @@ -1120,37 +1116,38 @@ class ConfigControllerTest extends WallabagCoreTestCase $this->logInAs('admin'); $client = $this->getTestClient(); - $client->request('GET', '/unread/list'); + $crawler = $client->request('GET', '/unread/list'); $this->assertStringContainsString('row data', $client->getResponse()->getContent()); - $client->request('GET', '/config/view-mode'); - $crawler = $client->followRedirect(); + $form = $crawler->filter('.nb-results')->selectButton('view_list')->form(); - $client->request('GET', '/unread/list'); + $client->submit($form); + + $client->followRedirect(); $this->assertStringContainsString('collection', $client->getResponse()->getContent()); - - $client->request('GET', '/config/view-mode'); } public function testChangeLocaleWithoutReferer() { $client = $this->getTestClient(); - $client->request('GET', '/locale/de'); - $client->followRedirect(); + $crawler = $client->request('POST', '/locale/de'); - $this->assertSame('de', $client->getRequest()->getLocale()); - $this->assertSame('de', $client->getContainer()->get(SessionInterface::class)->get('_locale')); + $this->assertSame(400, $client->getResponse()->getStatusCode()); + $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text'])); + $this->assertStringContainsString('Bad CSRF token.', $body[0]); } public function testChangeLocaleWithReferer() { $client = $this->getTestClient(); - $client->request('GET', '/login'); - $client->request('GET', '/locale/de'); + $crawler = $client->request('GET', '/login'); + + $client->submit($crawler->selectButton('Deutsch')->form()); + $client->followRedirect(); $this->assertSame('de', $client->getRequest()->getLocale()); @@ -1161,8 +1158,12 @@ class ConfigControllerTest extends WallabagCoreTestCase { $client = $this->getTestClient(); - $client->request('GET', '/login'); - $client->request('GET', '/locale/yuyuyuyu'); + $crawler = $client->request('GET', '/login'); + $token = $crawler->filter('form[action="/locale/de"] input[name=token]')->attr('value'); + + $client->request('POST', '/locale/yuyuyuyu', [ + 'token' => $token, + ]); $client->followRedirect(); $this->assertNotSame('yuyuyuyu', $client->getRequest()->getLocale()); @@ -1382,7 +1383,5 @@ class ConfigControllerTest extends WallabagCoreTestCase $client->request('GET', '/unread/list'); $this->assertStringNotContainsString('class="preview"', $client->getResponse()->getContent()); - - $client->request('GET', '/config/view-mode'); } } diff --git a/tests/Wallabag/CoreBundle/Controller/EntryControllerTest.php b/tests/Wallabag/CoreBundle/Controller/EntryControllerTest.php index 78143770e..f8f47d8b7 100644 --- a/tests/Wallabag/CoreBundle/Controller/EntryControllerTest.php +++ b/tests/Wallabag/CoreBundle/Controller/EntryControllerTest.php @@ -509,7 +509,9 @@ class EntryControllerTest extends WallabagCoreTestCase $this->getEntityManager()->flush(); $this->getEntityManager()->clear(); - $client->request('GET', '/reload/' . $entry->getId()); + $crawler = $client->request('GET', '/view/' . $entry->getId()); + + $client->submit($crawler->selectButton('entry.view.left_menu.re_fetch_content')->form()); $this->assertSame(302, $client->getResponse()->getStatusCode()); @@ -530,7 +532,9 @@ class EntryControllerTest extends WallabagCoreTestCase $this->getEntityManager()->persist($entry); $this->getEntityManager()->flush(); - $client->request('GET', '/reload/' . $entry->getId()); + $crawler = $client->request('GET', '/view/' . $entry->getId()); + + $client->submit($crawler->selectButton('entry.view.left_menu.re_fetch_content')->form()); $this->assertSame(302, $client->getResponse()->getStatusCode()); @@ -641,7 +645,9 @@ class EntryControllerTest extends WallabagCoreTestCase $this->getEntityManager()->flush(); $this->getEntityManager()->clear(); - $client->request('GET', '/archive/' . $entry->getId()); + $crawler = $client->request('GET', '/view/' . $entry->getId()); + + $client->submit($crawler->filter('.left-bar')->selectButton('entry.view.left_menu.set_as_read')->form()); $this->assertSame(302, $client->getResponse()->getStatusCode()); @@ -664,7 +670,9 @@ class EntryControllerTest extends WallabagCoreTestCase $this->getEntityManager()->flush(); $this->getEntityManager()->clear(); - $client->request('GET', '/star/' . $entry->getId()); + $crawler = $client->request('GET', '/view/' . $entry->getId()); + + $client->submit($crawler->filter('.left-bar')->selectButton('entry.view.left_menu.set_as_starred')->form()); $this->assertSame(302, $client->getResponse()->getStatusCode()); @@ -686,13 +694,11 @@ class EntryControllerTest extends WallabagCoreTestCase $this->getEntityManager()->persist($entry); $this->getEntityManager()->flush(); - $client->request('GET', '/delete/' . $entry->getId()); + $crawler = $client->request('POST', '/delete/' . $entry->getId()); - $this->assertSame(302, $client->getResponse()->getStatusCode()); - - $client->request('GET', '/delete/' . $entry->getId()); - - $this->assertSame(404, $client->getResponse()->getStatusCode()); + $this->assertSame(400, $client->getResponse()->getStatusCode()); + $this->assertGreaterThan(1, $body = $crawler->filter('body')->extract(['_text'])); + $this->assertStringContainsString('Bad CSRF token.', $body[0]); } /** @@ -728,10 +734,11 @@ class EntryControllerTest extends WallabagCoreTestCase $em->persist($content); $em->flush(); - $client->request('GET', '/view/' . $content->getId()); + $crawler = $client->request('GET', '/view/' . $content->getId()); $this->assertSame(200, $client->getResponse()->getStatusCode()); - $client->request('GET', '/delete/' . $content->getId()); + $client->submit($crawler->filter('.left-bar')->selectButton('entry.view.left_menu.delete')->form()); + $this->assertSame(302, $client->getResponse()->getStatusCode()); $client->followRedirect(); @@ -1148,7 +1155,10 @@ class EntryControllerTest extends WallabagCoreTestCase $this->assertSame(404, $client->getResponse()->getStatusCode()); // generating the uid - $client->request('GET', '/share/' . $content->getId()); + $crawler = $client->request('GET', '/view/' . $content->getId()); + + $client->submit($crawler->filter('.left-bar')->selectButton('entry.view.left_menu.public_link')->form()); + $this->assertSame(302, $client->getResponse()->getStatusCode()); $shareUrl = $client->getResponse()->getTargetUrl(); @@ -1175,12 +1185,19 @@ class EntryControllerTest extends WallabagCoreTestCase $this->assertSame(404, $client->getResponse()->getStatusCode()); // removing the share - $client->request('GET', '/share/delete/' . $content->getId()); + $client->getContainer()->get(Config::class)->set('share_public', 1); + $this->logInAs('admin'); + $crawler = $client->request('GET', '/view/' . $content->getId()); + + $client->submit($crawler->filter('.left-bar')->selectButton('entry.view.left_menu.delete_public_link')->form()); + $this->assertSame(302, $client->getResponse()->getStatusCode()); - // share is now disable + // share is now removed $client->request('GET', '/share/' . $content->getUid()); $this->assertSame(404, $client->getResponse()->getStatusCode()); + + $client->getContainer()->get(Config::class)->set('share_public', 0); } /** @@ -1256,7 +1273,9 @@ class EntryControllerTest extends WallabagCoreTestCase ->getRepository(Entry::class) ->findByUrlAndUserId($url, $this->getLoggedInUserId()); - $client->request('GET', '/delete/' . $content->getId()); + $crawler = $client->request('GET', '/view/' . $content->getId()); + + $client->submit($crawler->filter('.left-bar')->selectButton('entry.view.left_menu.delete')->form()); $this->assertSame(302, $client->getResponse()->getStatusCode()); @@ -1279,8 +1298,9 @@ class EntryControllerTest extends WallabagCoreTestCase $this->getEntityManager()->flush(); - $client->request('GET', '/view/' . $entry->getId()); - $client->request('GET', '/archive/' . $entry->getId()); + $crawler = $client->request('GET', '/view/' . $entry->getId()); + + $client->submit($crawler->filter('.left-bar')->selectButton('entry.view.left_menu.set_as_read')->form()); $this->assertSame(302, $client->getResponse()->getStatusCode()); $this->assertSame('/', $client->getResponse()->headers->get('location')); @@ -1304,8 +1324,7 @@ class EntryControllerTest extends WallabagCoreTestCase $crawler = $client->request('GET', '/view/' . $entry->getId()); - $link = $crawler->filter('a[id="markAsRead"]')->link(); - $client->click($link); + $client->submit($crawler->filter('.left-bar')->selectButton('entry.view.left_menu.set_as_read')->form()); $this->assertSame(302, $client->getResponse()->getStatusCode()); $this->assertStringContainsString('/view/' . $entry->getId(), $client->getResponse()->headers->get('location')); @@ -1429,7 +1448,8 @@ class EntryControllerTest extends WallabagCoreTestCase $crawler = $client->submit($form, $data); $this->assertCount(1, $crawler->filter($this->entryDataTestAttribute)); - $client->request('GET', '/delete/' . $entry->getId()); + + $client->submit($crawler->filter('.tools, .tools-list')->selectButton('delete')->form()); // test on list of all articles $crawler = $client->request('GET', '/all/list'); @@ -1500,8 +1520,8 @@ class EntryControllerTest extends WallabagCoreTestCase $crawler = $client->submit($form, $data); $currentUrl = $client->getRequest()->getUri(); - $element = $crawler->filter('a[data-action="delete"]')->link(); - $client->click($element); + $form = $crawler->filter('.tools, .tools-list')->selectButton('delete')->form(); + $client->submit($form); $client->followRedirect(); $nextUrl = $client->getRequest()->getUri(); $this->assertSame($currentUrl, $nextUrl); @@ -1674,7 +1694,7 @@ class EntryControllerTest extends WallabagCoreTestCase $this->assertSame('example.com', $content->getDomainName()); } - public function testEntryDeleteTagLink() + public function testEntryDeleteTagForm() { $this->logInAs('admin'); $client = $this->getTestClient(); @@ -1685,10 +1705,7 @@ class EntryControllerTest extends WallabagCoreTestCase $crawler = $client->request('GET', '/view/' . $entry->getId()); - // As long as the deletion link of a tag is following - // a link to the tag view, we take the second one to retrieve - // the deletion link of the first tag - $link = $crawler->filter('body div#article div.tools ul.tags li.chip a')->extract(['href'])[1]; + $link = $crawler->filter('body div#article div.tools ul.tags li.chip form')->extract(['action'])[0]; $this->assertStringStartsWith(sprintf('/remove-tag/%s/%s', $entry->getId(), $tag->getId()), $link); } @@ -1744,11 +1761,15 @@ class EntryControllerTest extends WallabagCoreTestCase $this->getEntityManager()->clear(); $entries = []; - $entries[] = $entry1->getId(); - $entries[] = $entry2->getId(); + $entries[] = $entry1Id = $entry1->getId(); + $entries[] = $entry2Id = $entry2->getId(); + + $crawler = $client->request('GET', '/all/list'); + $token = $crawler->filter('#form_mass_action input[name=token]')->attr('value'); // Mass actions : archive $client->request('POST', '/mass', [ + 'token' => $token, 'toggle-archive' => '', 'entry-checkbox' => $entries, ]); @@ -1769,8 +1790,12 @@ class EntryControllerTest extends WallabagCoreTestCase $this->assertSame(1, $res->isArchived()); + $crawler = $client->request('GET', '/all/list'); + $token = $crawler->filter('#form_mass_action input[name=token]')->attr('value'); + // Mass actions : star $client->request('POST', '/mass', [ + 'token' => $token, 'toggle-star' => '', 'entry-checkbox' => $entries, ]); @@ -1791,8 +1816,12 @@ class EntryControllerTest extends WallabagCoreTestCase $this->assertSame(1, $res->isStarred()); + $crawler = $client->request('GET', '/all/list'); + $token = $crawler->filter('#form_mass_action input[name=token]')->attr('value'); + // Mass actions : tag $client->request('POST', '/mass', [ + 'token' => $token, 'tag' => '', 'tags' => 'foo', 'entry-checkbox' => $entries, @@ -1821,17 +1850,29 @@ class EntryControllerTest extends WallabagCoreTestCase $this->assertNotContains('foo', $res->getTagsLabel()); + $crawler = $client->request('GET', '/all/list'); + $token = $crawler->filter('#form_mass_action input[name=token]')->attr('value'); + // Mass actions : delete $client->request('POST', '/mass', [ + 'token' => $token, 'delete' => '', 'entry-checkbox' => $entries, ]); - $client->request('GET', '/delete/' . $entry1->getId()); - $this->assertSame(404, $client->getResponse()->getStatusCode()); + $res = $client->getContainer() + ->get(EntityManagerInterface::class) + ->getRepository(Entry::class) + ->find($entry1Id); - $client->request('GET', '/delete/' . $entry2->getId()); - $this->assertSame(404, $client->getResponse()->getStatusCode()); + $this->assertNull($res); + + $res = $client->getContainer() + ->get(EntityManagerInterface::class) + ->getRepository(Entry::class) + ->find($entry2Id); + + $this->assertNull($res); } public function testGetSameDomainEntries() diff --git a/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php b/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php index 9c5f61fd0..a49656c94 100644 --- a/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php +++ b/tests/Wallabag/CoreBundle/Controller/TagControllerTest.php @@ -126,8 +126,8 @@ class TagControllerTest extends WallabagCoreTestCase $crawler = $client->request('GET', '/view/' . $entry->getId()); $entryUri = $client->getRequest()->getRequestUri(); - $link = $crawler->filter('a[href^="/remove-tag/' . $entry->getId() . '/' . $tag->getId() . '"]')->link(); - $client->click($link); + $form = $crawler->filter('form[action^="/remove-tag/' . $entry->getId() . '/' . $tag->getId() . '"]')->form(); + $client->submit($form); $this->assertSame(302, $client->getResponse()->getStatusCode()); $this->assertSame($entryUri, $client->getResponse()->getTargetUrl()); @@ -136,9 +136,8 @@ class TagControllerTest extends WallabagCoreTestCase $entry = $this->getEntityManager()->getRepository(Entry::class)->find($entry->getId()); $this->assertNotContains($this->tagName, $entry->getTagsLabel()); - $client->request('GET', '/remove-tag/' . $entry->getId() . '/' . $tag->getId()); - - $this->assertSame(404, $client->getResponse()->getStatusCode()); + $client->request('GET', '/view/' . $entry->getId()); + $this->assertStringNotContainsString('/remove-tag/' . $entry->getId() . '/' . $tag->getId(), $client->getResponse()->getContent()); $tag = $client->getContainer() ->get(EntityManagerInterface::class) @@ -169,8 +168,8 @@ class TagControllerTest extends WallabagCoreTestCase $this->getEntityManager()->clear(); $crawler = $client->request('GET', '/tag/list'); - $link = $crawler->filter('a[id="delete-' . $tag->getSlug() . '"]')->link(); - $client->click($link); + $form = $crawler->filter('#tag-' . $tag->getId())->selectButton('delete')->form(); + $client->submit($form); $tag = $client->getContainer() ->get(EntityManagerInterface::class) @@ -548,7 +547,7 @@ class TagControllerTest extends WallabagCoreTestCase $crawler = $client->submit($form, $data); - $client->click($crawler->selectLink('entry.list.assign_search_tag')->link()); + $client->submit($crawler->selectButton('entry.list.assign_search_tag')->form()); $client->followRedirect(); $entries = $client->getContainer()