diff options
Diffstat (limited to 'src/Wallabag/CoreBundle/Controller')
-rw-r--r-- | src/Wallabag/CoreBundle/Controller/ConfigController.php | 278 | ||||
-rw-r--r-- | src/Wallabag/CoreBundle/Controller/EntryController.php | 177 | ||||
-rw-r--r-- | src/Wallabag/CoreBundle/Controller/ExportController.php | 8 | ||||
-rw-r--r-- | src/Wallabag/CoreBundle/Controller/FeedController.php (renamed from src/Wallabag/CoreBundle/Controller/RssController.php) | 96 | ||||
-rw-r--r-- | src/Wallabag/CoreBundle/Controller/SiteCredentialController.php | 23 | ||||
-rw-r--r-- | src/Wallabag/CoreBundle/Controller/StaticController.php | 2 | ||||
-rw-r--r-- | src/Wallabag/CoreBundle/Controller/TagController.php | 57 |
7 files changed, 442 insertions, 199 deletions
diff --git a/src/Wallabag/CoreBundle/Controller/ConfigController.php b/src/Wallabag/CoreBundle/Controller/ConfigController.php index b999c539..6655ef93 100644 --- a/src/Wallabag/CoreBundle/Controller/ConfigController.php +++ b/src/Wallabag/CoreBundle/Controller/ConfigController.php | |||
@@ -2,17 +2,23 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\CoreBundle\Controller; | 3 | namespace Wallabag\CoreBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | 5 | use JMS\Serializer\SerializationContext; |
6 | use JMS\Serializer\SerializerBuilder; | ||
7 | use PragmaRX\Recovery\Recovery as BackupCodes; | ||
6 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 8 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
7 | use Symfony\Component\HttpFoundation\JsonResponse; | 9 | use Symfony\Component\HttpFoundation\JsonResponse; |
8 | use Symfony\Component\HttpFoundation\RedirectResponse; | 10 | use Symfony\Component\HttpFoundation\RedirectResponse; |
9 | use Symfony\Component\HttpFoundation\Request; | 11 | use Symfony\Component\HttpFoundation\Request; |
12 | use Symfony\Component\HttpFoundation\Response; | ||
10 | use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; | 13 | use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; |
14 | use Symfony\Component\Routing\Annotation\Route; | ||
15 | use Symfony\Component\Validator\Constraints\Locale as LocaleConstraint; | ||
11 | use Wallabag\CoreBundle\Entity\Config; | 16 | use Wallabag\CoreBundle\Entity\Config; |
12 | use Wallabag\CoreBundle\Entity\TaggingRule; | 17 | use Wallabag\CoreBundle\Entity\TaggingRule; |
13 | use Wallabag\CoreBundle\Form\Type\ChangePasswordType; | 18 | use Wallabag\CoreBundle\Form\Type\ChangePasswordType; |
14 | use Wallabag\CoreBundle\Form\Type\ConfigType; | 19 | use Wallabag\CoreBundle\Form\Type\ConfigType; |
15 | use Wallabag\CoreBundle\Form\Type\RssType; | 20 | use Wallabag\CoreBundle\Form\Type\FeedType; |
21 | use Wallabag\CoreBundle\Form\Type\TaggingRuleImportType; | ||
16 | use Wallabag\CoreBundle\Form\Type\TaggingRuleType; | 22 | use Wallabag\CoreBundle\Form\Type\TaggingRuleType; |
17 | use Wallabag\CoreBundle\Form\Type\UserInformationType; | 23 | use Wallabag\CoreBundle\Form\Type\UserInformationType; |
18 | use Wallabag\CoreBundle\Tools\Utils; | 24 | use Wallabag\CoreBundle\Tools\Utils; |
@@ -20,8 +26,6 @@ use Wallabag\CoreBundle\Tools\Utils; | |||
20 | class ConfigController extends Controller | 26 | class ConfigController extends Controller |
21 | { | 27 | { |
22 | /** | 28 | /** |
23 | * @param Request $request | ||
24 | * | ||
25 | * @Route("/config", name="config") | 29 | * @Route("/config", name="config") |
26 | */ | 30 | */ |
27 | public function indexAction(Request $request) | 31 | public function indexAction(Request $request) |
@@ -45,7 +49,7 @@ class ConfigController extends Controller | |||
45 | $activeTheme = $this->get('liip_theme.active_theme'); | 49 | $activeTheme = $this->get('liip_theme.active_theme'); |
46 | $activeTheme->setName($config->getTheme()); | 50 | $activeTheme->setName($config->getTheme()); |
47 | 51 | ||
48 | $this->get('session')->getFlashBag()->add( | 52 | $this->addFlash( |
49 | 'notice', | 53 | 'notice', |
50 | 'flashes.config.notice.config_saved' | 54 | 'flashes.config.notice.config_saved' |
51 | ); | 55 | ); |
@@ -67,7 +71,7 @@ class ConfigController extends Controller | |||
67 | $userManager->updateUser($user, true); | 71 | $userManager->updateUser($user, true); |
68 | } | 72 | } |
69 | 73 | ||
70 | $this->get('session')->getFlashBag()->add('notice', $message); | 74 | $this->addFlash('notice', $message); |
71 | 75 | ||
72 | return $this->redirect($this->generateUrl('config') . '#set4'); | 76 | return $this->redirect($this->generateUrl('config') . '#set4'); |
73 | } | 77 | } |
@@ -82,7 +86,7 @@ class ConfigController extends Controller | |||
82 | if ($userForm->isSubmitted() && $userForm->isValid()) { | 86 | if ($userForm->isSubmitted() && $userForm->isValid()) { |
83 | $userManager->updateUser($user, true); | 87 | $userManager->updateUser($user, true); |
84 | 88 | ||
85 | $this->get('session')->getFlashBag()->add( | 89 | $this->addFlash( |
86 | 'notice', | 90 | 'notice', |
87 | 'flashes.config.notice.user_updated' | 91 | 'flashes.config.notice.user_updated' |
88 | ); | 92 | ); |
@@ -90,17 +94,17 @@ class ConfigController extends Controller | |||
90 | return $this->redirect($this->generateUrl('config') . '#set3'); | 94 | return $this->redirect($this->generateUrl('config') . '#set3'); |
91 | } | 95 | } |
92 | 96 | ||
93 | // handle rss information | 97 | // handle feed information |
94 | $rssForm = $this->createForm(RssType::class, $config, ['action' => $this->generateUrl('config') . '#set2']); | 98 | $feedForm = $this->createForm(FeedType::class, $config, ['action' => $this->generateUrl('config') . '#set2']); |
95 | $rssForm->handleRequest($request); | 99 | $feedForm->handleRequest($request); |
96 | 100 | ||
97 | if ($rssForm->isSubmitted() && $rssForm->isValid()) { | 101 | if ($feedForm->isSubmitted() && $feedForm->isValid()) { |
98 | $em->persist($config); | 102 | $em->persist($config); |
99 | $em->flush(); | 103 | $em->flush(); |
100 | 104 | ||
101 | $this->get('session')->getFlashBag()->add( | 105 | $this->addFlash( |
102 | 'notice', | 106 | 'notice', |
103 | 'flashes.config.notice.rss_updated' | 107 | 'flashes.config.notice.feed_updated' |
104 | ); | 108 | ); |
105 | 109 | ||
106 | return $this->redirect($this->generateUrl('config') . '#set2'); | 110 | return $this->redirect($this->generateUrl('config') . '#set2'); |
@@ -130,7 +134,7 @@ class ConfigController extends Controller | |||
130 | $em->persist($taggingRule); | 134 | $em->persist($taggingRule); |
131 | $em->flush(); | 135 | $em->flush(); |
132 | 136 | ||
133 | $this->get('session')->getFlashBag()->add( | 137 | $this->addFlash( |
134 | 'notice', | 138 | 'notice', |
135 | 'flashes.config.notice.tagging_rules_updated' | 139 | 'flashes.config.notice.tagging_rules_updated' |
136 | ); | 140 | ); |
@@ -138,28 +142,168 @@ class ConfigController extends Controller | |||
138 | return $this->redirect($this->generateUrl('config') . '#set5'); | 142 | return $this->redirect($this->generateUrl('config') . '#set5'); |
139 | } | 143 | } |
140 | 144 | ||
145 | // handle tagging rules import | ||
146 | $taggingRulesImportform = $this->createForm(TaggingRuleImportType::class); | ||
147 | $taggingRulesImportform->handleRequest($request); | ||
148 | |||
149 | if ($taggingRulesImportform->isSubmitted() && $taggingRulesImportform->isValid()) { | ||
150 | $message = 'flashes.config.notice.tagging_rules_not_imported'; | ||
151 | $file = $taggingRulesImportform->get('file')->getData(); | ||
152 | |||
153 | if (null !== $file && $file->isValid() && \in_array($file->getClientMimeType(), ['application/json', 'application/octet-stream'], true)) { | ||
154 | $content = json_decode(file_get_contents($file->getPathname()), true); | ||
155 | |||
156 | if (\is_array($content)) { | ||
157 | foreach ($content as $rule) { | ||
158 | $taggingRule = new TaggingRule(); | ||
159 | $taggingRule->setRule($rule['rule']); | ||
160 | $taggingRule->setTags($rule['tags']); | ||
161 | $taggingRule->setConfig($config); | ||
162 | $em->persist($taggingRule); | ||
163 | } | ||
164 | |||
165 | $em->flush(); | ||
166 | |||
167 | $message = 'flashes.config.notice.tagging_rules_imported'; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | $this->addFlash('notice', $message); | ||
172 | |||
173 | return $this->redirect($this->generateUrl('config') . '#set5'); | ||
174 | } | ||
175 | |||
141 | return $this->render('WallabagCoreBundle:Config:index.html.twig', [ | 176 | return $this->render('WallabagCoreBundle:Config:index.html.twig', [ |
142 | 'form' => [ | 177 | 'form' => [ |
143 | 'config' => $configForm->createView(), | 178 | 'config' => $configForm->createView(), |
144 | 'rss' => $rssForm->createView(), | 179 | 'feed' => $feedForm->createView(), |
145 | 'pwd' => $pwdForm->createView(), | 180 | 'pwd' => $pwdForm->createView(), |
146 | 'user' => $userForm->createView(), | 181 | 'user' => $userForm->createView(), |
147 | 'new_tagging_rule' => $newTaggingRule->createView(), | 182 | 'new_tagging_rule' => $newTaggingRule->createView(), |
183 | 'import_tagging_rule' => $taggingRulesImportform->createView(), | ||
148 | ], | 184 | ], |
149 | 'rss' => [ | 185 | 'feed' => [ |
150 | 'username' => $user->getUsername(), | 186 | 'username' => $user->getUsername(), |
151 | 'token' => $config->getRssToken(), | 187 | 'token' => $config->getFeedToken(), |
152 | ], | 188 | ], |
153 | 'twofactor_auth' => $this->getParameter('twofactor_auth'), | 189 | 'twofactor_auth' => $this->getParameter('twofactor_auth'), |
154 | 'wallabag_url' => $this->getParameter('domain_name'), | 190 | 'wallabag_url' => $this->getParameter('domain_name'), |
155 | 'enabled_users' => $this->get('wallabag_user.user_repository') | 191 | 'enabled_users' => $this->get('wallabag_user.user_repository')->getSumEnabledUsers(), |
156 | ->getSumEnabledUsers(), | 192 | ]); |
193 | } | ||
194 | |||
195 | /** | ||
196 | * Enable 2FA using email. | ||
197 | * | ||
198 | * @Route("/config/otp/email", name="config_otp_email") | ||
199 | */ | ||
200 | public function otpEmailAction() | ||
201 | { | ||
202 | if (!$this->getParameter('twofactor_auth')) { | ||
203 | return $this->createNotFoundException('two_factor not enabled'); | ||
204 | } | ||
205 | |||
206 | $user = $this->getUser(); | ||
207 | |||
208 | $user->setGoogleAuthenticatorSecret(null); | ||
209 | $user->setBackupCodes(null); | ||
210 | $user->setEmailTwoFactor(true); | ||
211 | |||
212 | $this->container->get('fos_user.user_manager')->updateUser($user, true); | ||
213 | |||
214 | $this->addFlash( | ||
215 | 'notice', | ||
216 | 'flashes.config.notice.otp_enabled' | ||
217 | ); | ||
218 | |||
219 | return $this->redirect($this->generateUrl('config') . '#set3'); | ||
220 | } | ||
221 | |||
222 | /** | ||
223 | * Enable 2FA using OTP app, user will need to confirm the generated code from the app. | ||
224 | * | ||
225 | * @Route("/config/otp/app", name="config_otp_app") | ||
226 | */ | ||
227 | public function otpAppAction() | ||
228 | { | ||
229 | if (!$this->getParameter('twofactor_auth')) { | ||
230 | return $this->createNotFoundException('two_factor not enabled'); | ||
231 | } | ||
232 | |||
233 | $user = $this->getUser(); | ||
234 | $secret = $this->get('scheb_two_factor.security.google_authenticator')->generateSecret(); | ||
235 | |||
236 | $user->setGoogleAuthenticatorSecret($secret); | ||
237 | $user->setEmailTwoFactor(false); | ||
238 | |||
239 | $backupCodes = (new BackupCodes())->toArray(); | ||
240 | $backupCodesHashed = array_map( | ||
241 | function ($backupCode) { | ||
242 | return password_hash($backupCode, PASSWORD_DEFAULT); | ||
243 | }, | ||
244 | $backupCodes | ||
245 | ); | ||
246 | |||
247 | $user->setBackupCodes($backupCodesHashed); | ||
248 | |||
249 | $this->container->get('fos_user.user_manager')->updateUser($user, true); | ||
250 | |||
251 | return $this->render('WallabagCoreBundle:Config:otp_app.html.twig', [ | ||
252 | 'backupCodes' => $backupCodes, | ||
253 | 'qr_code' => $this->get('scheb_two_factor.security.google_authenticator')->getQRContent($user), | ||
157 | ]); | 254 | ]); |
158 | } | 255 | } |
159 | 256 | ||
160 | /** | 257 | /** |
161 | * @param Request $request | 258 | * Cancelling 2FA using OTP app. |
162 | * | 259 | * |
260 | * @Route("/config/otp/app/cancel", name="config_otp_app_cancel") | ||
261 | */ | ||
262 | public function otpAppCancelAction() | ||
263 | { | ||
264 | if (!$this->getParameter('twofactor_auth')) { | ||
265 | return $this->createNotFoundException('two_factor not enabled'); | ||
266 | } | ||
267 | |||
268 | $user = $this->getUser(); | ||
269 | $user->setGoogleAuthenticatorSecret(null); | ||
270 | $user->setBackupCodes(null); | ||
271 | |||
272 | $this->container->get('fos_user.user_manager')->updateUser($user, true); | ||
273 | |||
274 | return $this->redirect($this->generateUrl('config') . '#set3'); | ||
275 | } | ||
276 | |||
277 | /** | ||
278 | * Validate OTP code. | ||
279 | * | ||
280 | * @Route("/config/otp/app/check", name="config_otp_app_check") | ||
281 | */ | ||
282 | public function otpAppCheckAction(Request $request) | ||
283 | { | ||
284 | $isValid = $this->get('scheb_two_factor.security.google_authenticator')->checkCode( | ||
285 | $this->getUser(), | ||
286 | $request->get('_auth_code') | ||
287 | ); | ||
288 | |||
289 | if (true === $isValid) { | ||
290 | $this->addFlash( | ||
291 | 'notice', | ||
292 | 'flashes.config.notice.otp_enabled' | ||
293 | ); | ||
294 | |||
295 | return $this->redirect($this->generateUrl('config') . '#set3'); | ||
296 | } | ||
297 | |||
298 | $this->addFlash( | ||
299 | 'two_factor', | ||
300 | 'scheb_two_factor.code_invalid' | ||
301 | ); | ||
302 | |||
303 | return $this->redirect($this->generateUrl('config_otp_app')); | ||
304 | } | ||
305 | |||
306 | /** | ||
163 | * @Route("/generate-token", name="generate_token") | 307 | * @Route("/generate-token", name="generate_token") |
164 | * | 308 | * |
165 | * @return RedirectResponse|JsonResponse | 309 | * @return RedirectResponse|JsonResponse |
@@ -167,28 +311,52 @@ class ConfigController extends Controller | |||
167 | public function generateTokenAction(Request $request) | 311 | public function generateTokenAction(Request $request) |
168 | { | 312 | { |
169 | $config = $this->getConfig(); | 313 | $config = $this->getConfig(); |
170 | $config->setRssToken(Utils::generateToken()); | 314 | $config->setFeedToken(Utils::generateToken()); |
171 | 315 | ||
172 | $em = $this->getDoctrine()->getManager(); | 316 | $em = $this->getDoctrine()->getManager(); |
173 | $em->persist($config); | 317 | $em->persist($config); |
174 | $em->flush(); | 318 | $em->flush(); |
175 | 319 | ||
176 | if ($request->isXmlHttpRequest()) { | 320 | if ($request->isXmlHttpRequest()) { |
177 | return new JsonResponse(['token' => $config->getRssToken()]); | 321 | return new JsonResponse(['token' => $config->getFeedToken()]); |
178 | } | 322 | } |
179 | 323 | ||
180 | $this->get('session')->getFlashBag()->add( | 324 | $this->addFlash( |
181 | 'notice', | 325 | 'notice', |
182 | 'flashes.config.notice.rss_token_updated' | 326 | 'flashes.config.notice.feed_token_updated' |
183 | ); | 327 | ); |
184 | 328 | ||
185 | return $this->redirect($this->generateUrl('config') . '#set2'); | 329 | return $this->redirect($this->generateUrl('config') . '#set2'); |
186 | } | 330 | } |
187 | 331 | ||
188 | /** | 332 | /** |
189 | * Deletes a tagging rule and redirect to the config homepage. | 333 | * @Route("/revoke-token", name="revoke_token") |
190 | * | 334 | * |
191 | * @param TaggingRule $rule | 335 | * @return RedirectResponse|JsonResponse |
336 | */ | ||
337 | public function revokeTokenAction(Request $request) | ||
338 | { | ||
339 | $config = $this->getConfig(); | ||
340 | $config->setFeedToken(null); | ||
341 | |||
342 | $em = $this->getDoctrine()->getManager(); | ||
343 | $em->persist($config); | ||
344 | $em->flush(); | ||
345 | |||
346 | if ($request->isXmlHttpRequest()) { | ||
347 | return new JsonResponse(); | ||
348 | } | ||
349 | |||
350 | $this->addFlash( | ||
351 | 'notice', | ||
352 | 'flashes.config.notice.feed_token_revoked' | ||
353 | ); | ||
354 | |||
355 | return $this->redirect($this->generateUrl('config') . '#set2'); | ||
356 | } | ||
357 | |||
358 | /** | ||
359 | * Deletes a tagging rule and redirect to the config homepage. | ||
192 | * | 360 | * |
193 | * @Route("/tagging-rule/delete/{id}", requirements={"id" = "\d+"}, name="delete_tagging_rule") | 361 | * @Route("/tagging-rule/delete/{id}", requirements={"id" = "\d+"}, name="delete_tagging_rule") |
194 | * | 362 | * |
@@ -202,7 +370,7 @@ class ConfigController extends Controller | |||
202 | $em->remove($rule); | 370 | $em->remove($rule); |
203 | $em->flush(); | 371 | $em->flush(); |
204 | 372 | ||
205 | $this->get('session')->getFlashBag()->add( | 373 | $this->addFlash( |
206 | 'notice', | 374 | 'notice', |
207 | 'flashes.config.notice.tagging_rules_deleted' | 375 | 'flashes.config.notice.tagging_rules_deleted' |
208 | ); | 376 | ); |
@@ -213,8 +381,6 @@ class ConfigController extends Controller | |||
213 | /** | 381 | /** |
214 | * Edit a tagging rule. | 382 | * Edit a tagging rule. |
215 | * | 383 | * |
216 | * @param TaggingRule $rule | ||
217 | * | ||
218 | * @Route("/tagging-rule/edit/{id}", requirements={"id" = "\d+"}, name="edit_tagging_rule") | 384 | * @Route("/tagging-rule/edit/{id}", requirements={"id" = "\d+"}, name="edit_tagging_rule") |
219 | * | 385 | * |
220 | * @return RedirectResponse | 386 | * @return RedirectResponse |
@@ -268,7 +434,7 @@ class ConfigController extends Controller | |||
268 | break; | 434 | break; |
269 | } | 435 | } |
270 | 436 | ||
271 | $this->get('session')->getFlashBag()->add( | 437 | $this->addFlash( |
272 | 'notice', | 438 | 'notice', |
273 | 'flashes.config.notice.' . $type . '_reset' | 439 | 'flashes.config.notice.' . $type . '_reset' |
274 | ); | 440 | ); |
@@ -281,8 +447,6 @@ class ConfigController extends Controller | |||
281 | * | 447 | * |
282 | * @Route("/account/delete", name="delete_account") | 448 | * @Route("/account/delete", name="delete_account") |
283 | * | 449 | * |
284 | * @param Request $request | ||
285 | * | ||
286 | * @throws AccessDeniedHttpException | 450 | * @throws AccessDeniedHttpException |
287 | * | 451 | * |
288 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | 452 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
@@ -313,8 +477,6 @@ class ConfigController extends Controller | |||
313 | * | 477 | * |
314 | * @Route("/config/view-mode", name="switch_view_mode") | 478 | * @Route("/config/view-mode", name="switch_view_mode") |
315 | * | 479 | * |
316 | * @param Request $request | ||
317 | * | ||
318 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | 480 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
319 | */ | 481 | */ |
320 | public function changeViewModeAction(Request $request) | 482 | public function changeViewModeAction(Request $request) |
@@ -330,6 +492,52 @@ class ConfigController extends Controller | |||
330 | } | 492 | } |
331 | 493 | ||
332 | /** | 494 | /** |
495 | * Change the locale for the current user. | ||
496 | * | ||
497 | * @param string $language | ||
498 | * | ||
499 | * @Route("/locale/{language}", name="changeLocale") | ||
500 | * | ||
501 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | ||
502 | */ | ||
503 | public function setLocaleAction(Request $request, $language = null) | ||
504 | { | ||
505 | $errors = $this->get('validator')->validate($language, (new LocaleConstraint())); | ||
506 | |||
507 | if (0 === \count($errors)) { | ||
508 | $request->getSession()->set('_locale', $language); | ||
509 | } | ||
510 | |||
511 | return $this->redirect($request->headers->get('referer', $this->generateUrl('homepage'))); | ||
512 | } | ||
513 | |||
514 | /** | ||
515 | * Export tagging rules for the logged in user. | ||
516 | * | ||
517 | * @Route("/tagging-rule/export", name="export_tagging_rule") | ||
518 | * | ||
519 | * @return Response | ||
520 | */ | ||
521 | public function exportTaggingRulesAction() | ||
522 | { | ||
523 | $data = SerializerBuilder::create()->build()->serialize( | ||
524 | $this->getUser()->getConfig()->getTaggingRules(), | ||
525 | 'json', | ||
526 | SerializationContext::create()->setGroups(['export_tagging_rule']) | ||
527 | ); | ||
528 | |||
529 | return Response::create( | ||
530 | $data, | ||
531 | 200, | ||
532 | [ | ||
533 | 'Content-type' => 'application/json', | ||
534 | 'Content-Disposition' => 'attachment; filename="tagging_rules_' . $this->getUser()->getUsername() . '.json"', | ||
535 | 'Content-Transfer-Encoding' => 'UTF-8', | ||
536 | ] | ||
537 | ); | ||
538 | } | ||
539 | |||
540 | /** | ||
333 | * Remove all tags for given tags and a given user and cleanup orphan tags. | 541 | * Remove all tags for given tags and a given user and cleanup orphan tags. |
334 | * | 542 | * |
335 | * @param array $tags | 543 | * @param array $tags |
@@ -395,8 +603,6 @@ class ConfigController extends Controller | |||
395 | 603 | ||
396 | /** | 604 | /** |
397 | * Validate that a rule can be edited/deleted by the current user. | 605 | * Validate that a rule can be edited/deleted by the current user. |
398 | * | ||
399 | * @param TaggingRule $rule | ||
400 | */ | 606 | */ |
401 | private function validateRuleAction(TaggingRule $rule) | 607 | private function validateRuleAction(TaggingRule $rule) |
402 | { | 608 | { |
diff --git a/src/Wallabag/CoreBundle/Controller/EntryController.php b/src/Wallabag/CoreBundle/Controller/EntryController.php index b7fdea27..ba5bfbe2 100644 --- a/src/Wallabag/CoreBundle/Controller/EntryController.php +++ b/src/Wallabag/CoreBundle/Controller/EntryController.php | |||
@@ -2,12 +2,13 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\CoreBundle\Controller; | 3 | namespace Wallabag\CoreBundle\Controller; |
4 | 4 | ||
5 | use Doctrine\ORM\NoResultException; | ||
5 | use Pagerfanta\Adapter\DoctrineORMAdapter; | 6 | use Pagerfanta\Adapter\DoctrineORMAdapter; |
6 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; | 7 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; |
7 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache; | 8 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache; |
8 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
9 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 9 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
10 | use Symfony\Component\HttpFoundation\Request; | 10 | use Symfony\Component\HttpFoundation\Request; |
11 | use Symfony\Component\Routing\Annotation\Route; | ||
11 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; | 12 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; |
12 | use Wallabag\CoreBundle\Entity\Entry; | 13 | use Wallabag\CoreBundle\Entity\Entry; |
13 | use Wallabag\CoreBundle\Event\EntryDeletedEvent; | 14 | use Wallabag\CoreBundle\Event\EntryDeletedEvent; |
@@ -20,8 +21,7 @@ use Wallabag\CoreBundle\Form\Type\SearchEntryType; | |||
20 | class EntryController extends Controller | 21 | class EntryController extends Controller |
21 | { | 22 | { |
22 | /** | 23 | /** |
23 | * @param Request $request | 24 | * @param int $page |
24 | * @param int $page | ||
25 | * | 25 | * |
26 | * @Route("/search/{page}", name="search", defaults={"page" = 1}) | 26 | * @Route("/search/{page}", name="search", defaults={"page" = 1}) |
27 | * | 27 | * |
@@ -52,8 +52,6 @@ class EntryController extends Controller | |||
52 | } | 52 | } |
53 | 53 | ||
54 | /** | 54 | /** |
55 | * @param Request $request | ||
56 | * | ||
57 | * @Route("/new-entry", name="new_entry") | 55 | * @Route("/new-entry", name="new_entry") |
58 | * | 56 | * |
59 | * @return \Symfony\Component\HttpFoundation\Response | 57 | * @return \Symfony\Component\HttpFoundation\Response |
@@ -96,8 +94,6 @@ class EntryController extends Controller | |||
96 | } | 94 | } |
97 | 95 | ||
98 | /** | 96 | /** |
99 | * @param Request $request | ||
100 | * | ||
101 | * @Route("/bookmarklet", name="bookmarklet") | 97 | * @Route("/bookmarklet", name="bookmarklet") |
102 | * | 98 | * |
103 | * @return \Symfony\Component\HttpFoundation\Response | 99 | * @return \Symfony\Component\HttpFoundation\Response |
@@ -134,9 +130,6 @@ class EntryController extends Controller | |||
134 | /** | 130 | /** |
135 | * Edit an entry content. | 131 | * Edit an entry content. |
136 | * | 132 | * |
137 | * @param Request $request | ||
138 | * @param Entry $entry | ||
139 | * | ||
140 | * @Route("/edit/{id}", requirements={"id" = "\d+"}, name="edit") | 133 | * @Route("/edit/{id}", requirements={"id" = "\d+"}, name="edit") |
141 | * | 134 | * |
142 | * @return \Symfony\Component\HttpFoundation\Response | 135 | * @return \Symfony\Component\HttpFoundation\Response |
@@ -170,8 +163,7 @@ class EntryController extends Controller | |||
170 | /** | 163 | /** |
171 | * Shows all entries for current user. | 164 | * Shows all entries for current user. |
172 | * | 165 | * |
173 | * @param Request $request | 166 | * @param int $page |
174 | * @param int $page | ||
175 | * | 167 | * |
176 | * @Route("/all/list/{page}", name="all", defaults={"page" = "1"}) | 168 | * @Route("/all/list/{page}", name="all", defaults={"page" = "1"}) |
177 | * | 169 | * |
@@ -185,8 +177,7 @@ class EntryController extends Controller | |||
185 | /** | 177 | /** |
186 | * Shows unread entries for current user. | 178 | * Shows unread entries for current user. |
187 | * | 179 | * |
188 | * @param Request $request | 180 | * @param int $page |
189 | * @param int $page | ||
190 | * | 181 | * |
191 | * @Route("/unread/list/{page}", name="unread", defaults={"page" = "1"}) | 182 | * @Route("/unread/list/{page}", name="unread", defaults={"page" = "1"}) |
192 | * | 183 | * |
@@ -205,8 +196,7 @@ class EntryController extends Controller | |||
205 | /** | 196 | /** |
206 | * Shows read entries for current user. | 197 | * Shows read entries for current user. |
207 | * | 198 | * |
208 | * @param Request $request | 199 | * @param int $page |
209 | * @param int $page | ||
210 | * | 200 | * |
211 | * @Route("/archive/list/{page}", name="archive", defaults={"page" = "1"}) | 201 | * @Route("/archive/list/{page}", name="archive", defaults={"page" = "1"}) |
212 | * | 202 | * |
@@ -220,8 +210,7 @@ class EntryController extends Controller | |||
220 | /** | 210 | /** |
221 | * Shows starred entries for current user. | 211 | * Shows starred entries for current user. |
222 | * | 212 | * |
223 | * @param Request $request | 213 | * @param int $page |
224 | * @param int $page | ||
225 | * | 214 | * |
226 | * @Route("/starred/list/{page}", name="starred", defaults={"page" = "1"}) | 215 | * @Route("/starred/list/{page}", name="starred", defaults={"page" = "1"}) |
227 | * | 216 | * |
@@ -233,9 +222,46 @@ class EntryController extends Controller | |||
233 | } | 222 | } |
234 | 223 | ||
235 | /** | 224 | /** |
236 | * Shows entry content. | 225 | * Shows untagged articles for current user. |
226 | * | ||
227 | * @param int $page | ||
228 | * | ||
229 | * @Route("/untagged/list/{page}", name="untagged", defaults={"page" = "1"}) | ||
237 | * | 230 | * |
238 | * @param Entry $entry | 231 | * @return \Symfony\Component\HttpFoundation\Response |
232 | */ | ||
233 | public function showUntaggedEntriesAction(Request $request, $page) | ||
234 | { | ||
235 | return $this->showEntries('untagged', $request, $page); | ||
236 | } | ||
237 | |||
238 | /** | ||
239 | * Shows random entry depending on the given type. | ||
240 | * | ||
241 | * @param string $type | ||
242 | * | ||
243 | * @Route("/{type}/random", name="random_entry", requirements={"type": "unread|starred|archive|untagged|all"}) | ||
244 | * | ||
245 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | ||
246 | */ | ||
247 | public function redirectRandomEntryAction($type = 'all') | ||
248 | { | ||
249 | try { | ||
250 | $entry = $this->get('wallabag_core.entry_repository') | ||
251 | ->getRandomEntry($this->getUser()->getId(), $type); | ||
252 | } catch (NoResultException $e) { | ||
253 | $bag = $this->get('session')->getFlashBag(); | ||
254 | $bag->clear(); | ||
255 | $bag->add('notice', 'flashes.entry.notice.no_random_entry'); | ||
256 | |||
257 | return $this->redirect($this->generateUrl($type)); | ||
258 | } | ||
259 | |||
260 | return $this->redirect($this->generateUrl('view', ['id' => $entry->getId()])); | ||
261 | } | ||
262 | |||
263 | /** | ||
264 | * Shows entry content. | ||
239 | * | 265 | * |
240 | * @Route("/view/{id}", requirements={"id" = "\d+"}, name="view") | 266 | * @Route("/view/{id}", requirements={"id" = "\d+"}, name="view") |
241 | * | 267 | * |
@@ -255,8 +281,6 @@ class EntryController extends Controller | |||
255 | * Reload an entry. | 281 | * Reload an entry. |
256 | * Refetch content from the website and make it readable again. | 282 | * Refetch content from the website and make it readable again. |
257 | * | 283 | * |
258 | * @param Entry $entry | ||
259 | * | ||
260 | * @Route("/reload/{id}", requirements={"id" = "\d+"}, name="reload_entry") | 284 | * @Route("/reload/{id}", requirements={"id" = "\d+"}, name="reload_entry") |
261 | * | 285 | * |
262 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | 286 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
@@ -289,9 +313,6 @@ class EntryController extends Controller | |||
289 | /** | 313 | /** |
290 | * Changes read status for an entry. | 314 | * Changes read status for an entry. |
291 | * | 315 | * |
292 | * @param Request $request | ||
293 | * @param Entry $entry | ||
294 | * | ||
295 | * @Route("/archive/{id}", requirements={"id" = "\d+"}, name="archive_entry") | 316 | * @Route("/archive/{id}", requirements={"id" = "\d+"}, name="archive_entry") |
296 | * | 317 | * |
297 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | 318 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
@@ -321,9 +342,6 @@ class EntryController extends Controller | |||
321 | /** | 342 | /** |
322 | * Changes starred status for an entry. | 343 | * Changes starred status for an entry. |
323 | * | 344 | * |
324 | * @param Request $request | ||
325 | * @param Entry $entry | ||
326 | * | ||
327 | * @Route("/star/{id}", requirements={"id" = "\d+"}, name="star_entry") | 345 | * @Route("/star/{id}", requirements={"id" = "\d+"}, name="star_entry") |
328 | * | 346 | * |
329 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | 347 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
@@ -354,8 +372,6 @@ class EntryController extends Controller | |||
354 | /** | 372 | /** |
355 | * Deletes entry and redirect to the homepage or the last viewed page. | 373 | * Deletes entry and redirect to the homepage or the last viewed page. |
356 | * | 374 | * |
357 | * @param Entry $entry | ||
358 | * | ||
359 | * @Route("/delete/{id}", requirements={"id" = "\d+"}, name="delete_entry") | 375 | * @Route("/delete/{id}", requirements={"id" = "\d+"}, name="delete_entry") |
360 | * | 376 | * |
361 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | 377 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
@@ -396,8 +412,6 @@ class EntryController extends Controller | |||
396 | /** | 412 | /** |
397 | * Get public URL for entry (and generate it if necessary). | 413 | * Get public URL for entry (and generate it if necessary). |
398 | * | 414 | * |
399 | * @param Entry $entry | ||
400 | * | ||
401 | * @Route("/share/{id}", requirements={"id" = "\d+"}, name="share") | 415 | * @Route("/share/{id}", requirements={"id" = "\d+"}, name="share") |
402 | * | 416 | * |
403 | * @return \Symfony\Component\HttpFoundation\Response | 417 | * @return \Symfony\Component\HttpFoundation\Response |
@@ -422,8 +436,6 @@ class EntryController extends Controller | |||
422 | /** | 436 | /** |
423 | * Disable public sharing for an entry. | 437 | * Disable public sharing for an entry. |
424 | * | 438 | * |
425 | * @param Entry $entry | ||
426 | * | ||
427 | * @Route("/share/delete/{id}", requirements={"id" = "\d+"}, name="delete_share") | 439 | * @Route("/share/delete/{id}", requirements={"id" = "\d+"}, name="delete_share") |
428 | * | 440 | * |
429 | * @return \Symfony\Component\HttpFoundation\Response | 441 | * @return \Symfony\Component\HttpFoundation\Response |
@@ -446,8 +458,6 @@ class EntryController extends Controller | |||
446 | /** | 458 | /** |
447 | * Ability to view a content publicly. | 459 | * Ability to view a content publicly. |
448 | * | 460 | * |
449 | * @param Entry $entry | ||
450 | * | ||
451 | * @Route("/share/{uid}", requirements={"uid" = ".+"}, name="share_entry") | 461 | * @Route("/share/{uid}", requirements={"uid" = ".+"}, name="share_entry") |
452 | * @Cache(maxage="25200", smaxage="25200", public=true) | 462 | * @Cache(maxage="25200", smaxage="25200", public=true) |
453 | * | 463 | * |
@@ -466,60 +476,11 @@ class EntryController extends Controller | |||
466 | } | 476 | } |
467 | 477 | ||
468 | /** | 478 | /** |
469 | * Shows untagged articles for current user. | ||
470 | * | ||
471 | * @param Request $request | ||
472 | * @param int $page | ||
473 | * | ||
474 | * @Route("/untagged/list/{page}", name="untagged", defaults={"page" = "1"}) | ||
475 | * | ||
476 | * @return \Symfony\Component\HttpFoundation\Response | ||
477 | */ | ||
478 | public function showUntaggedEntriesAction(Request $request, $page) | ||
479 | { | ||
480 | return $this->showEntries('untagged', $request, $page); | ||
481 | } | ||
482 | |||
483 | /** | ||
484 | * Fetch content and update entry. | ||
485 | * In case it fails, $entry->getContent will return an error message. | ||
486 | * | ||
487 | * @param Entry $entry | ||
488 | * @param string $prefixMessage Should be the translation key: entry_saved or entry_reloaded | ||
489 | */ | ||
490 | private function updateEntry(Entry $entry, $prefixMessage = 'entry_saved') | ||
491 | { | ||
492 | $message = 'flashes.entry.notice.' . $prefixMessage; | ||
493 | |||
494 | try { | ||
495 | $this->get('wallabag_core.content_proxy')->updateEntry($entry, $entry->getUrl()); | ||
496 | } catch (\Exception $e) { | ||
497 | $this->get('logger')->error('Error while saving an entry', [ | ||
498 | 'exception' => $e, | ||
499 | 'entry' => $entry, | ||
500 | ]); | ||
501 | |||
502 | $message = 'flashes.entry.notice.' . $prefixMessage . '_failed'; | ||
503 | } | ||
504 | |||
505 | if (empty($entry->getDomainName())) { | ||
506 | $this->get('wallabag_core.content_proxy')->setEntryDomainName($entry); | ||
507 | } | ||
508 | |||
509 | if (empty($entry->getTitle())) { | ||
510 | $this->get('wallabag_core.content_proxy')->setDefaultEntryTitle($entry); | ||
511 | } | ||
512 | |||
513 | $this->get('session')->getFlashBag()->add('notice', $message); | ||
514 | } | ||
515 | |||
516 | /** | ||
517 | * Global method to retrieve entries depending on the given type | 479 | * Global method to retrieve entries depending on the given type |
518 | * It returns the response to be send. | 480 | * It returns the response to be send. |
519 | * | 481 | * |
520 | * @param string $type Entries type: unread, starred or archive | 482 | * @param string $type Entries type: unread, starred or archive |
521 | * @param Request $request | 483 | * @param int $page |
522 | * @param int $page | ||
523 | * | 484 | * |
524 | * @return \Symfony\Component\HttpFoundation\Response | 485 | * @return \Symfony\Component\HttpFoundation\Response |
525 | */ | 486 | */ |
@@ -532,11 +493,9 @@ class EntryController extends Controller | |||
532 | switch ($type) { | 493 | switch ($type) { |
533 | case 'search': | 494 | case 'search': |
534 | $qb = $repository->getBuilderForSearchByUser($this->getUser()->getId(), $searchTerm, $currentRoute); | 495 | $qb = $repository->getBuilderForSearchByUser($this->getUser()->getId(), $searchTerm, $currentRoute); |
535 | |||
536 | break; | 496 | break; |
537 | case 'untagged': | 497 | case 'untagged': |
538 | $qb = $repository->getBuilderForUntaggedByUser($this->getUser()->getId()); | 498 | $qb = $repository->getBuilderForUntaggedByUser($this->getUser()->getId()); |
539 | |||
540 | break; | 499 | break; |
541 | case 'starred': | 500 | case 'starred': |
542 | $qb = $repository->getBuilderForStarredByUser($this->getUser()->getId()); | 501 | $qb = $repository->getBuilderForStarredByUser($this->getUser()->getId()); |
@@ -576,6 +535,9 @@ class EntryController extends Controller | |||
576 | } | 535 | } |
577 | } | 536 | } |
578 | 537 | ||
538 | $nbEntriesUntagged = $this->get('wallabag_core.entry_repository') | ||
539 | ->countUntaggedEntriesByUser($this->getUser()->getId()); | ||
540 | |||
579 | return $this->render( | 541 | return $this->render( |
580 | 'WallabagCoreBundle:Entry:entries.html.twig', [ | 542 | 'WallabagCoreBundle:Entry:entries.html.twig', [ |
581 | 'form' => $form->createView(), | 543 | 'form' => $form->createView(), |
@@ -583,14 +545,45 @@ class EntryController extends Controller | |||
583 | 'currentPage' => $page, | 545 | 'currentPage' => $page, |
584 | 'searchTerm' => $searchTerm, | 546 | 'searchTerm' => $searchTerm, |
585 | 'isFiltered' => $form->isSubmitted(), | 547 | 'isFiltered' => $form->isSubmitted(), |
548 | 'nbEntriesUntagged' => $nbEntriesUntagged, | ||
586 | ] | 549 | ] |
587 | ); | 550 | ); |
588 | } | 551 | } |
589 | 552 | ||
590 | /** | 553 | /** |
591 | * Check if the logged user can manage the given entry. | 554 | * Fetch content and update entry. |
555 | * In case it fails, $entry->getContent will return an error message. | ||
592 | * | 556 | * |
593 | * @param Entry $entry | 557 | * @param string $prefixMessage Should be the translation key: entry_saved or entry_reloaded |
558 | */ | ||
559 | private function updateEntry(Entry $entry, $prefixMessage = 'entry_saved') | ||
560 | { | ||
561 | $message = 'flashes.entry.notice.' . $prefixMessage; | ||
562 | |||
563 | try { | ||
564 | $this->get('wallabag_core.content_proxy')->updateEntry($entry, $entry->getUrl()); | ||
565 | } catch (\Exception $e) { | ||
566 | $this->get('logger')->error('Error while saving an entry', [ | ||
567 | 'exception' => $e, | ||
568 | 'entry' => $entry, | ||
569 | ]); | ||
570 | |||
571 | $message = 'flashes.entry.notice.' . $prefixMessage . '_failed'; | ||
572 | } | ||
573 | |||
574 | if (empty($entry->getDomainName())) { | ||
575 | $this->get('wallabag_core.content_proxy')->setEntryDomainName($entry); | ||
576 | } | ||
577 | |||
578 | if (empty($entry->getTitle())) { | ||
579 | $this->get('wallabag_core.content_proxy')->setDefaultEntryTitle($entry); | ||
580 | } | ||
581 | |||
582 | $this->get('session')->getFlashBag()->add('notice', $message); | ||
583 | } | ||
584 | |||
585 | /** | ||
586 | * Check if the logged user can manage the given entry. | ||
594 | */ | 587 | */ |
595 | private function checkUserAction(Entry $entry) | 588 | private function checkUserAction(Entry $entry) |
596 | { | 589 | { |
@@ -602,8 +595,6 @@ class EntryController extends Controller | |||
602 | /** | 595 | /** |
603 | * Check for existing entry, if it exists, redirect to it with a message. | 596 | * Check for existing entry, if it exists, redirect to it with a message. |
604 | * | 597 | * |
605 | * @param Entry $entry | ||
606 | * | ||
607 | * @return Entry|bool | 598 | * @return Entry|bool |
608 | */ | 599 | */ |
609 | private function checkIfEntryAlreadyExists(Entry $entry) | 600 | private function checkIfEntryAlreadyExists(Entry $entry) |
diff --git a/src/Wallabag/CoreBundle/Controller/ExportController.php b/src/Wallabag/CoreBundle/Controller/ExportController.php index 7ca89239..282fd733 100644 --- a/src/Wallabag/CoreBundle/Controller/ExportController.php +++ b/src/Wallabag/CoreBundle/Controller/ExportController.php | |||
@@ -2,10 +2,10 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\CoreBundle\Controller; | 3 | namespace Wallabag\CoreBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
6 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 5 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
7 | use Symfony\Component\HttpFoundation\Request; | 6 | use Symfony\Component\HttpFoundation\Request; |
8 | use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; | 7 | use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; |
8 | use Symfony\Component\Routing\Annotation\Route; | ||
9 | use Wallabag\CoreBundle\Entity\Entry; | 9 | use Wallabag\CoreBundle\Entity\Entry; |
10 | 10 | ||
11 | /** | 11 | /** |
@@ -17,7 +17,6 @@ class ExportController extends Controller | |||
17 | /** | 17 | /** |
18 | * Gets one entry content. | 18 | * Gets one entry content. |
19 | * | 19 | * |
20 | * @param Entry $entry | ||
21 | * @param string $format | 20 | * @param string $format |
22 | * | 21 | * |
23 | * @Route("/export/{id}.{format}", name="export_entry", requirements={ | 22 | * @Route("/export/{id}.{format}", name="export_entry", requirements={ |
@@ -58,6 +57,7 @@ class ExportController extends Controller | |||
58 | $method = ucfirst($category); | 57 | $method = ucfirst($category); |
59 | $methodBuilder = 'getBuilderFor' . $method . 'ByUser'; | 58 | $methodBuilder = 'getBuilderFor' . $method . 'ByUser'; |
60 | $repository = $this->get('wallabag_core.entry_repository'); | 59 | $repository = $this->get('wallabag_core.entry_repository'); |
60 | $title = $method; | ||
61 | 61 | ||
62 | if ('tag_entries' === $category) { | 62 | if ('tag_entries' === $category) { |
63 | $tag = $this->get('wallabag_core.tag_repository')->findOneBySlug($request->query->get('tag')); | 63 | $tag = $this->get('wallabag_core.tag_repository')->findOneBySlug($request->query->get('tag')); |
@@ -66,6 +66,8 @@ class ExportController extends Controller | |||
66 | $this->getUser()->getId(), | 66 | $this->getUser()->getId(), |
67 | $tag->getId() | 67 | $tag->getId() |
68 | ); | 68 | ); |
69 | |||
70 | $title = 'Tag ' . $tag->getLabel(); | ||
69 | } else { | 71 | } else { |
70 | $entries = $repository | 72 | $entries = $repository |
71 | ->$methodBuilder($this->getUser()->getId()) | 73 | ->$methodBuilder($this->getUser()->getId()) |
@@ -76,7 +78,7 @@ class ExportController extends Controller | |||
76 | try { | 78 | try { |
77 | return $this->get('wallabag_core.helper.entries_export') | 79 | return $this->get('wallabag_core.helper.entries_export') |
78 | ->setEntries($entries) | 80 | ->setEntries($entries) |
79 | ->updateTitle($method) | 81 | ->updateTitle($title) |
80 | ->updateAuthor($method) | 82 | ->updateAuthor($method) |
81 | ->exportAs($format); | 83 | ->exportAs($format); |
82 | } catch (\InvalidArgumentException $e) { | 84 | } catch (\InvalidArgumentException $e) { |
diff --git a/src/Wallabag/CoreBundle/Controller/RssController.php b/src/Wallabag/CoreBundle/Controller/FeedController.php index 848bb814..95c3427b 100644 --- a/src/Wallabag/CoreBundle/Controller/RssController.php +++ b/src/Wallabag/CoreBundle/Controller/FeedController.php | |||
@@ -7,86 +7,94 @@ use Pagerfanta\Adapter\DoctrineORMAdapter; | |||
7 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; | 7 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; |
8 | use Pagerfanta\Pagerfanta; | 8 | use Pagerfanta\Pagerfanta; |
9 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; | 9 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; |
10 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
11 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 10 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
12 | use Symfony\Component\HttpFoundation\Request; | ||
13 | use Symfony\Component\HttpFoundation\Response; | 11 | use Symfony\Component\HttpFoundation\Response; |
12 | use Symfony\Component\Routing\Annotation\Route; | ||
14 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; | 13 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; |
15 | use Wallabag\CoreBundle\Entity\Tag; | 14 | use Wallabag\CoreBundle\Entity\Tag; |
16 | use Wallabag\UserBundle\Entity\User; | 15 | use Wallabag\UserBundle\Entity\User; |
17 | 16 | ||
18 | class RssController extends Controller | 17 | class FeedController extends Controller |
19 | { | 18 | { |
20 | /** | 19 | /** |
21 | * Shows unread entries for current user. | 20 | * Shows unread entries for current user. |
22 | * | 21 | * |
23 | * @Route("/{username}/{token}/unread.xml", name="unread_rss", defaults={"_format"="xml"}) | 22 | * @Route("/feed/{username}/{token}/unread/{page}", name="unread_feed", defaults={"page"=1, "_format"="xml"}) |
24 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") | 23 | * |
24 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_feed_token_converter") | ||
25 | * | ||
26 | * @param $page | ||
25 | * | 27 | * |
26 | * @return \Symfony\Component\HttpFoundation\Response | 28 | * @return \Symfony\Component\HttpFoundation\Response |
27 | */ | 29 | */ |
28 | public function showUnreadRSSAction(Request $request, User $user) | 30 | public function showUnreadFeedAction(User $user, $page) |
29 | { | 31 | { |
30 | return $this->showEntries('unread', $user, $request->query->get('page', 1)); | 32 | return $this->showEntries('unread', $user, $page); |
31 | } | 33 | } |
32 | 34 | ||
33 | /** | 35 | /** |
34 | * Shows read entries for current user. | 36 | * Shows read entries for current user. |
35 | * | 37 | * |
36 | * @Route("/{username}/{token}/archive.xml", name="archive_rss", defaults={"_format"="xml"}) | 38 | * @Route("/feed/{username}/{token}/archive/{page}", name="archive_feed", defaults={"page"=1, "_format"="xml"}) |
37 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") | 39 | * |
40 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_feed_token_converter") | ||
41 | * | ||
42 | * @param $page | ||
38 | * | 43 | * |
39 | * @return \Symfony\Component\HttpFoundation\Response | 44 | * @return \Symfony\Component\HttpFoundation\Response |
40 | */ | 45 | */ |
41 | public function showArchiveRSSAction(Request $request, User $user) | 46 | public function showArchiveFeedAction(User $user, $page) |
42 | { | 47 | { |
43 | return $this->showEntries('archive', $user, $request->query->get('page', 1)); | 48 | return $this->showEntries('archive', $user, $page); |
44 | } | 49 | } |
45 | 50 | ||
46 | /** | 51 | /** |
47 | * Shows starred entries for current user. | 52 | * Shows starred entries for current user. |
48 | * | 53 | * |
49 | * @Route("/{username}/{token}/starred.xml", name="starred_rss", defaults={"_format"="xml"}) | 54 | * @Route("/feed/{username}/{token}/starred/{page}", name="starred_feed", defaults={"page"=1, "_format"="xml"}) |
50 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") | 55 | * |
56 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_feed_token_converter") | ||
57 | * | ||
58 | * @param $page | ||
51 | * | 59 | * |
52 | * @return \Symfony\Component\HttpFoundation\Response | 60 | * @return \Symfony\Component\HttpFoundation\Response |
53 | */ | 61 | */ |
54 | public function showStarredRSSAction(Request $request, User $user) | 62 | public function showStarredFeedAction(User $user, $page) |
55 | { | 63 | { |
56 | return $this->showEntries('starred', $user, $request->query->get('page', 1)); | 64 | return $this->showEntries('starred', $user, $page); |
57 | } | 65 | } |
58 | 66 | ||
59 | /** | 67 | /** |
60 | * Shows all entries for current user. | 68 | * Shows all entries for current user. |
61 | * | 69 | * |
62 | * @Route("/{username}/{token}/all.xml", name="all_rss", defaults={"_format"="xml"}) | 70 | * @Route("/feed/{username}/{token}/all/{page}", name="all_feed", defaults={"page"=1, "_format"="xml"}) |
63 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") | 71 | * |
72 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_feed_token_converter") | ||
64 | * | 73 | * |
65 | * @return \Symfony\Component\HttpFoundation\Response | 74 | * @return \Symfony\Component\HttpFoundation\Response |
66 | */ | 75 | */ |
67 | public function showAllRSSAction(Request $request, User $user) | 76 | public function showAllFeedAction(User $user, $page) |
68 | { | 77 | { |
69 | return $this->showEntries('all', $user, $request->query->get('page', 1)); | 78 | return $this->showEntries('all', $user, $page); |
70 | } | 79 | } |
71 | 80 | ||
72 | /** | 81 | /** |
73 | * Shows entries associated to a tag for current user. | 82 | * Shows entries associated to a tag for current user. |
74 | * | 83 | * |
75 | * @Route("/{username}/{token}/tags/{slug}.xml", name="tag_rss", defaults={"_format"="xml"}) | 84 | * @Route("/feed/{username}/{token}/tags/{slug}/{page}", name="tag_feed", defaults={"page"=1, "_format"="xml"}) |
76 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_rsstoken_converter") | 85 | * |
86 | * @ParamConverter("user", class="WallabagUserBundle:User", converter="username_feed_token_converter") | ||
77 | * @ParamConverter("tag", options={"mapping": {"slug": "slug"}}) | 87 | * @ParamConverter("tag", options={"mapping": {"slug": "slug"}}) |
78 | * | 88 | * |
79 | * @return \Symfony\Component\HttpFoundation\Response | 89 | * @return \Symfony\Component\HttpFoundation\Response |
80 | */ | 90 | */ |
81 | public function showTagsAction(Request $request, User $user, Tag $tag) | 91 | public function showTagsFeedAction(User $user, Tag $tag, $page) |
82 | { | 92 | { |
83 | $page = $request->query->get('page', 1); | ||
84 | |||
85 | $url = $this->generateUrl( | 93 | $url = $this->generateUrl( |
86 | 'tag_rss', | 94 | 'tag_feed', |
87 | [ | 95 | [ |
88 | 'username' => $user->getUsername(), | 96 | 'username' => $user->getUsername(), |
89 | 'token' => $user->getConfig()->getRssToken(), | 97 | 'token' => $user->getConfig()->getFeedToken(), |
90 | 'slug' => $tag->getSlug(), | 98 | 'slug' => $tag->getSlug(), |
91 | ], | 99 | ], |
92 | UrlGeneratorInterface::ABSOLUTE_URL | 100 | UrlGeneratorInterface::ABSOLUTE_URL |
@@ -119,12 +127,15 @@ class RssController extends Controller | |||
119 | return $this->render( | 127 | return $this->render( |
120 | '@WallabagCore/themes/common/Entry/entries.xml.twig', | 128 | '@WallabagCore/themes/common/Entry/entries.xml.twig', |
121 | [ | 129 | [ |
122 | 'url_html' => $this->generateUrl('tag_entries', ['slug' => $tag->getSlug()], UrlGeneratorInterface::ABSOLUTE_URL), | 130 | 'type' => 'tag', |
123 | 'type' => 'tag (' . $tag->getLabel() . ')', | ||
124 | 'url' => $url, | 131 | 'url' => $url, |
125 | 'entries' => $entries, | 132 | 'entries' => $entries, |
133 | 'user' => $user->getUsername(), | ||
134 | 'domainName' => $this->getParameter('domain_name'), | ||
135 | 'version' => $this->getParameter('wallabag_core.version'), | ||
136 | 'tag' => $tag->getSlug(), | ||
126 | ], | 137 | ], |
127 | new Response('', 200, ['Content-Type' => 'application/rss+xml']) | 138 | new Response('', 200, ['Content-Type' => 'application/atom+xml']) |
128 | ); | 139 | ); |
129 | } | 140 | } |
130 | 141 | ||
@@ -133,7 +144,6 @@ class RssController extends Controller | |||
133 | * It returns the response to be send. | 144 | * It returns the response to be send. |
134 | * | 145 | * |
135 | * @param string $type Entries type: unread, starred or archive | 146 | * @param string $type Entries type: unread, starred or archive |
136 | * @param User $user | ||
137 | * @param int $page | 147 | * @param int $page |
138 | * | 148 | * |
139 | * @return \Symfony\Component\HttpFoundation\Response | 149 | * @return \Symfony\Component\HttpFoundation\Response |
@@ -162,14 +172,14 @@ class RssController extends Controller | |||
162 | $pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false); | 172 | $pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false); |
163 | $entries = new Pagerfanta($pagerAdapter); | 173 | $entries = new Pagerfanta($pagerAdapter); |
164 | 174 | ||
165 | $perPage = $user->getConfig()->getRssLimit() ?: $this->getParameter('wallabag_core.rss_limit'); | 175 | $perPage = $user->getConfig()->getFeedLimit() ?: $this->getParameter('wallabag_core.feed_limit'); |
166 | $entries->setMaxPerPage($perPage); | 176 | $entries->setMaxPerPage($perPage); |
167 | 177 | ||
168 | $url = $this->generateUrl( | 178 | $url = $this->generateUrl( |
169 | $type . '_rss', | 179 | $type . '_feed', |
170 | [ | 180 | [ |
171 | 'username' => $user->getUsername(), | 181 | 'username' => $user->getUsername(), |
172 | 'token' => $user->getConfig()->getRssToken(), | 182 | 'token' => $user->getConfig()->getFeedToken(), |
173 | ], | 183 | ], |
174 | UrlGeneratorInterface::ABSOLUTE_URL | 184 | UrlGeneratorInterface::ABSOLUTE_URL |
175 | ); | 185 | ); |
@@ -178,19 +188,19 @@ class RssController extends Controller | |||
178 | $entries->setCurrentPage((int) $page); | 188 | $entries->setCurrentPage((int) $page); |
179 | } catch (OutOfRangeCurrentPageException $e) { | 189 | } catch (OutOfRangeCurrentPageException $e) { |
180 | if ($page > 1) { | 190 | if ($page > 1) { |
181 | return $this->redirect($url . '?page=' . $entries->getNbPages(), 302); | 191 | return $this->redirect($url . '/' . $entries->getNbPages()); |
182 | } | 192 | } |
183 | } | 193 | } |
184 | 194 | ||
185 | return $this->render( | 195 | return $this->render('@WallabagCore/themes/common/Entry/entries.xml.twig', [ |
186 | '@WallabagCore/themes/common/Entry/entries.xml.twig', | 196 | 'type' => $type, |
187 | [ | 197 | 'url' => $url, |
188 | 'url_html' => $this->generateUrl($type, [], UrlGeneratorInterface::ABSOLUTE_URL), | 198 | 'entries' => $entries, |
189 | 'type' => $type, | 199 | 'user' => $user->getUsername(), |
190 | 'url' => $url, | 200 | 'domainName' => $this->getParameter('domain_name'), |
191 | 'entries' => $entries, | 201 | 'version' => $this->getParameter('wallabag_core.version'), |
192 | ], | 202 | ], |
193 | new Response('', 200, ['Content-Type' => 'application/rss+xml']) | 203 | new Response('', 200, ['Content-Type' => 'application/atom+xml']) |
194 | ); | 204 | ); |
195 | } | 205 | } |
196 | } | 206 | } |
diff --git a/src/Wallabag/CoreBundle/Controller/SiteCredentialController.php b/src/Wallabag/CoreBundle/Controller/SiteCredentialController.php index 548de744..4320c5ff 100644 --- a/src/Wallabag/CoreBundle/Controller/SiteCredentialController.php +++ b/src/Wallabag/CoreBundle/Controller/SiteCredentialController.php | |||
@@ -2,10 +2,9 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\CoreBundle\Controller; | 3 | namespace Wallabag\CoreBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; | ||
6 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
7 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 5 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
8 | use Symfony\Component\HttpFoundation\Request; | 6 | use Symfony\Component\HttpFoundation\Request; |
7 | use Symfony\Component\Routing\Annotation\Route; | ||
9 | use Wallabag\CoreBundle\Entity\SiteCredential; | 8 | use Wallabag\CoreBundle\Entity\SiteCredential; |
10 | use Wallabag\UserBundle\Entity\User; | 9 | use Wallabag\UserBundle\Entity\User; |
11 | 10 | ||
@@ -19,8 +18,7 @@ class SiteCredentialController extends Controller | |||
19 | /** | 18 | /** |
20 | * Lists all User entities. | 19 | * Lists all User entities. |
21 | * | 20 | * |
22 | * @Route("/", name="site_credentials_index") | 21 | * @Route("/", name="site_credentials_index", methods={"GET"}) |
23 | * @Method("GET") | ||
24 | */ | 22 | */ |
25 | public function indexAction() | 23 | public function indexAction() |
26 | { | 24 | { |
@@ -36,10 +34,7 @@ class SiteCredentialController extends Controller | |||
36 | /** | 34 | /** |
37 | * Creates a new site credential entity. | 35 | * Creates a new site credential entity. |
38 | * | 36 | * |
39 | * @Route("/new", name="site_credentials_new") | 37 | * @Route("/new", name="site_credentials_new", methods={"GET", "POST"}) |
40 | * @Method({"GET", "POST"}) | ||
41 | * | ||
42 | * @param Request $request | ||
43 | * | 38 | * |
44 | * @return \Symfony\Component\HttpFoundation\Response | 39 | * @return \Symfony\Component\HttpFoundation\Response |
45 | */ | 40 | */ |
@@ -77,11 +72,7 @@ class SiteCredentialController extends Controller | |||
77 | /** | 72 | /** |
78 | * Displays a form to edit an existing site credential entity. | 73 | * Displays a form to edit an existing site credential entity. |
79 | * | 74 | * |
80 | * @Route("/{id}/edit", name="site_credentials_edit") | 75 | * @Route("/{id}/edit", name="site_credentials_edit", methods={"GET", "POST"}) |
81 | * @Method({"GET", "POST"}) | ||
82 | * | ||
83 | * @param Request $request | ||
84 | * @param SiteCredential $siteCredential | ||
85 | * | 76 | * |
86 | * @return \Symfony\Component\HttpFoundation\Response | 77 | * @return \Symfony\Component\HttpFoundation\Response |
87 | */ | 78 | */ |
@@ -121,11 +112,7 @@ class SiteCredentialController extends Controller | |||
121 | /** | 112 | /** |
122 | * Deletes a site credential entity. | 113 | * Deletes a site credential entity. |
123 | * | 114 | * |
124 | * @Route("/{id}", name="site_credentials_delete") | 115 | * @Route("/{id}", name="site_credentials_delete", methods={"DELETE"}) |
125 | * @Method("DELETE") | ||
126 | * | ||
127 | * @param Request $request | ||
128 | * @param SiteCredential $siteCredential | ||
129 | * | 116 | * |
130 | * @return \Symfony\Component\HttpFoundation\RedirectResponse | 117 | * @return \Symfony\Component\HttpFoundation\RedirectResponse |
131 | */ | 118 | */ |
diff --git a/src/Wallabag/CoreBundle/Controller/StaticController.php b/src/Wallabag/CoreBundle/Controller/StaticController.php index 318af303..fa760c14 100644 --- a/src/Wallabag/CoreBundle/Controller/StaticController.php +++ b/src/Wallabag/CoreBundle/Controller/StaticController.php | |||
@@ -2,8 +2,8 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\CoreBundle\Controller; | 3 | namespace Wallabag\CoreBundle\Controller; |
4 | 4 | ||
5 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
6 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 5 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
6 | use Symfony\Component\Routing\Annotation\Route; | ||
7 | 7 | ||
8 | class StaticController extends Controller | 8 | class StaticController extends Controller |
9 | { | 9 | { |
diff --git a/src/Wallabag/CoreBundle/Controller/TagController.php b/src/Wallabag/CoreBundle/Controller/TagController.php index b6d28e59..a6ad131f 100644 --- a/src/Wallabag/CoreBundle/Controller/TagController.php +++ b/src/Wallabag/CoreBundle/Controller/TagController.php | |||
@@ -5,19 +5,17 @@ namespace Wallabag\CoreBundle\Controller; | |||
5 | use Pagerfanta\Adapter\ArrayAdapter; | 5 | use Pagerfanta\Adapter\ArrayAdapter; |
6 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; | 6 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; |
7 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; | 7 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; |
8 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | ||
9 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 8 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
10 | use Symfony\Component\HttpFoundation\Request; | 9 | use Symfony\Component\HttpFoundation\Request; |
10 | use Symfony\Component\Routing\Annotation\Route; | ||
11 | use Wallabag\CoreBundle\Entity\Entry; | 11 | use Wallabag\CoreBundle\Entity\Entry; |
12 | use Wallabag\CoreBundle\Entity\Tag; | 12 | use Wallabag\CoreBundle\Entity\Tag; |
13 | use Wallabag\CoreBundle\Form\Type\NewTagType; | 13 | use Wallabag\CoreBundle\Form\Type\NewTagType; |
14 | use Wallabag\CoreBundle\Form\Type\RenameTagType; | ||
14 | 15 | ||
15 | class TagController extends Controller | 16 | class TagController extends Controller |
16 | { | 17 | { |
17 | /** | 18 | /** |
18 | * @param Request $request | ||
19 | * @param Entry $entry | ||
20 | * | ||
21 | * @Route("/new-tag/{entry}", requirements={"entry" = "\d+"}, name="new_tag") | 19 | * @Route("/new-tag/{entry}", requirements={"entry" = "\d+"}, name="new_tag") |
22 | * | 20 | * |
23 | * @return \Symfony\Component\HttpFoundation\Response | 21 | * @return \Symfony\Component\HttpFoundation\Response |
@@ -86,14 +84,22 @@ class TagController extends Controller | |||
86 | { | 84 | { |
87 | $tags = $this->get('wallabag_core.tag_repository') | 85 | $tags = $this->get('wallabag_core.tag_repository') |
88 | ->findAllFlatTagsWithNbEntries($this->getUser()->getId()); | 86 | ->findAllFlatTagsWithNbEntries($this->getUser()->getId()); |
87 | $nbEntriesUntagged = $this->get('wallabag_core.entry_repository') | ||
88 | ->countUntaggedEntriesByUser($this->getUser()->getId()); | ||
89 | |||
90 | $renameForms = []; | ||
91 | foreach ($tags as $tag) { | ||
92 | $renameForms[$tag['id']] = $this->createForm(RenameTagType::class, new Tag())->createView(); | ||
93 | } | ||
89 | 94 | ||
90 | return $this->render('WallabagCoreBundle:Tag:tags.html.twig', [ | 95 | return $this->render('WallabagCoreBundle:Tag:tags.html.twig', [ |
91 | 'tags' => $tags, | 96 | 'tags' => $tags, |
97 | 'renameForms' => $renameForms, | ||
98 | 'nbEntriesUntagged' => $nbEntriesUntagged, | ||
92 | ]); | 99 | ]); |
93 | } | 100 | } |
94 | 101 | ||
95 | /** | 102 | /** |
96 | * @param Tag $tag | ||
97 | * @param int $page | 103 | * @param int $page |
98 | * | 104 | * |
99 | * @Route("/tag/list/{slug}/{page}", name="tag_entries", defaults={"page" = "1"}) | 105 | * @Route("/tag/list/{slug}/{page}", name="tag_entries", defaults={"page" = "1"}) |
@@ -130,4 +136,45 @@ class TagController extends Controller | |||
130 | 'tag' => $tag, | 136 | 'tag' => $tag, |
131 | ]); | 137 | ]); |
132 | } | 138 | } |
139 | |||
140 | /** | ||
141 | * Rename a given tag with a new label | ||
142 | * Create a new tag with the new name and drop the old one. | ||
143 | * | ||
144 | * @Route("/tag/rename/{slug}", name="tag_rename") | ||
145 | * @ParamConverter("tag", options={"mapping": {"slug": "slug"}}) | ||
146 | * | ||
147 | * @return \Symfony\Component\HttpFoundation\Response | ||
148 | */ | ||
149 | public function renameTagAction(Tag $tag, Request $request) | ||
150 | { | ||
151 | $form = $this->createForm(RenameTagType::class, new Tag()); | ||
152 | $form->handleRequest($request); | ||
153 | |||
154 | if ($form->isSubmitted() && $form->isValid()) { | ||
155 | $entries = $this->get('wallabag_core.entry_repository')->findAllByTagId( | ||
156 | $this->getUser()->getId(), | ||
157 | $tag->getId() | ||
158 | ); | ||
159 | foreach ($entries as $entry) { | ||
160 | $this->get('wallabag_core.tags_assigner')->assignTagsToEntry( | ||
161 | $entry, | ||
162 | $form->get('label')->getData() | ||
163 | ); | ||
164 | $entry->removeTag($tag); | ||
165 | } | ||
166 | |||
167 | $em = $this->getDoctrine()->getManager(); | ||
168 | $em->flush(); | ||
169 | } | ||
170 | |||
171 | $this->get('session')->getFlashBag()->add( | ||
172 | 'notice', | ||
173 | 'flashes.tag.notice.tag_renamed' | ||
174 | ); | ||
175 | |||
176 | $redirectUrl = $this->get('wallabag_core.helper.redirect')->to($request->headers->get('referer'), '', true); | ||
177 | |||
178 | return $this->redirect($redirectUrl); | ||
179 | } | ||
133 | } | 180 | } |