aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/Wallabag/CoreBundle/Controller
diff options
context:
space:
mode:
Diffstat (limited to 'src/Wallabag/CoreBundle/Controller')
-rw-r--r--src/Wallabag/CoreBundle/Controller/ConfigController.php278
-rw-r--r--src/Wallabag/CoreBundle/Controller/EntryController.php177
-rw-r--r--src/Wallabag/CoreBundle/Controller/ExportController.php8
-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.php23
-rw-r--r--src/Wallabag/CoreBundle/Controller/StaticController.php2
-rw-r--r--src/Wallabag/CoreBundle/Controller/TagController.php57
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
3namespace Wallabag\CoreBundle\Controller; 3namespace Wallabag\CoreBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 5use JMS\Serializer\SerializationContext;
6use JMS\Serializer\SerializerBuilder;
7use PragmaRX\Recovery\Recovery as BackupCodes;
6use Symfony\Bundle\FrameworkBundle\Controller\Controller; 8use Symfony\Bundle\FrameworkBundle\Controller\Controller;
7use Symfony\Component\HttpFoundation\JsonResponse; 9use Symfony\Component\HttpFoundation\JsonResponse;
8use Symfony\Component\HttpFoundation\RedirectResponse; 10use Symfony\Component\HttpFoundation\RedirectResponse;
9use Symfony\Component\HttpFoundation\Request; 11use Symfony\Component\HttpFoundation\Request;
12use Symfony\Component\HttpFoundation\Response;
10use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; 13use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
14use Symfony\Component\Routing\Annotation\Route;
15use Symfony\Component\Validator\Constraints\Locale as LocaleConstraint;
11use Wallabag\CoreBundle\Entity\Config; 16use Wallabag\CoreBundle\Entity\Config;
12use Wallabag\CoreBundle\Entity\TaggingRule; 17use Wallabag\CoreBundle\Entity\TaggingRule;
13use Wallabag\CoreBundle\Form\Type\ChangePasswordType; 18use Wallabag\CoreBundle\Form\Type\ChangePasswordType;
14use Wallabag\CoreBundle\Form\Type\ConfigType; 19use Wallabag\CoreBundle\Form\Type\ConfigType;
15use Wallabag\CoreBundle\Form\Type\RssType; 20use Wallabag\CoreBundle\Form\Type\FeedType;
21use Wallabag\CoreBundle\Form\Type\TaggingRuleImportType;
16use Wallabag\CoreBundle\Form\Type\TaggingRuleType; 22use Wallabag\CoreBundle\Form\Type\TaggingRuleType;
17use Wallabag\CoreBundle\Form\Type\UserInformationType; 23use Wallabag\CoreBundle\Form\Type\UserInformationType;
18use Wallabag\CoreBundle\Tools\Utils; 24use Wallabag\CoreBundle\Tools\Utils;
@@ -20,8 +26,6 @@ use Wallabag\CoreBundle\Tools\Utils;
20class ConfigController extends Controller 26class 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
3namespace Wallabag\CoreBundle\Controller; 3namespace Wallabag\CoreBundle\Controller;
4 4
5use Doctrine\ORM\NoResultException;
5use Pagerfanta\Adapter\DoctrineORMAdapter; 6use Pagerfanta\Adapter\DoctrineORMAdapter;
6use Pagerfanta\Exception\OutOfRangeCurrentPageException; 7use Pagerfanta\Exception\OutOfRangeCurrentPageException;
7use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache; 8use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
8use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
9use Symfony\Bundle\FrameworkBundle\Controller\Controller; 9use Symfony\Bundle\FrameworkBundle\Controller\Controller;
10use Symfony\Component\HttpFoundation\Request; 10use Symfony\Component\HttpFoundation\Request;
11use Symfony\Component\Routing\Annotation\Route;
11use Symfony\Component\Routing\Generator\UrlGeneratorInterface; 12use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
12use Wallabag\CoreBundle\Entity\Entry; 13use Wallabag\CoreBundle\Entity\Entry;
13use Wallabag\CoreBundle\Event\EntryDeletedEvent; 14use Wallabag\CoreBundle\Event\EntryDeletedEvent;
@@ -20,8 +21,7 @@ use Wallabag\CoreBundle\Form\Type\SearchEntryType;
20class EntryController extends Controller 21class 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
3namespace Wallabag\CoreBundle\Controller; 3namespace Wallabag\CoreBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Bundle\FrameworkBundle\Controller\Controller; 5use Symfony\Bundle\FrameworkBundle\Controller\Controller;
7use Symfony\Component\HttpFoundation\Request; 6use Symfony\Component\HttpFoundation\Request;
8use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; 7use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
8use Symfony\Component\Routing\Annotation\Route;
9use Wallabag\CoreBundle\Entity\Entry; 9use 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;
7use Pagerfanta\Exception\OutOfRangeCurrentPageException; 7use Pagerfanta\Exception\OutOfRangeCurrentPageException;
8use Pagerfanta\Pagerfanta; 8use Pagerfanta\Pagerfanta;
9use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; 9use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
10use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
11use Symfony\Bundle\FrameworkBundle\Controller\Controller; 10use Symfony\Bundle\FrameworkBundle\Controller\Controller;
12use Symfony\Component\HttpFoundation\Request;
13use Symfony\Component\HttpFoundation\Response; 11use Symfony\Component\HttpFoundation\Response;
12use Symfony\Component\Routing\Annotation\Route;
14use Symfony\Component\Routing\Generator\UrlGeneratorInterface; 13use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
15use Wallabag\CoreBundle\Entity\Tag; 14use Wallabag\CoreBundle\Entity\Tag;
16use Wallabag\UserBundle\Entity\User; 15use Wallabag\UserBundle\Entity\User;
17 16
18class RssController extends Controller 17class 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
3namespace Wallabag\CoreBundle\Controller; 3namespace Wallabag\CoreBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
6use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
7use Symfony\Bundle\FrameworkBundle\Controller\Controller; 5use Symfony\Bundle\FrameworkBundle\Controller\Controller;
8use Symfony\Component\HttpFoundation\Request; 6use Symfony\Component\HttpFoundation\Request;
7use Symfony\Component\Routing\Annotation\Route;
9use Wallabag\CoreBundle\Entity\SiteCredential; 8use Wallabag\CoreBundle\Entity\SiteCredential;
10use Wallabag\UserBundle\Entity\User; 9use 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
3namespace Wallabag\CoreBundle\Controller; 3namespace Wallabag\CoreBundle\Controller;
4 4
5use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
6use Symfony\Bundle\FrameworkBundle\Controller\Controller; 5use Symfony\Bundle\FrameworkBundle\Controller\Controller;
6use Symfony\Component\Routing\Annotation\Route;
7 7
8class StaticController extends Controller 8class 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;
5use Pagerfanta\Adapter\ArrayAdapter; 5use Pagerfanta\Adapter\ArrayAdapter;
6use Pagerfanta\Exception\OutOfRangeCurrentPageException; 6use Pagerfanta\Exception\OutOfRangeCurrentPageException;
7use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; 7use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
8use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
9use Symfony\Bundle\FrameworkBundle\Controller\Controller; 8use Symfony\Bundle\FrameworkBundle\Controller\Controller;
10use Symfony\Component\HttpFoundation\Request; 9use Symfony\Component\HttpFoundation\Request;
10use Symfony\Component\Routing\Annotation\Route;
11use Wallabag\CoreBundle\Entity\Entry; 11use Wallabag\CoreBundle\Entity\Entry;
12use Wallabag\CoreBundle\Entity\Tag; 12use Wallabag\CoreBundle\Entity\Tag;
13use Wallabag\CoreBundle\Form\Type\NewTagType; 13use Wallabag\CoreBundle\Form\Type\NewTagType;
14use Wallabag\CoreBundle\Form\Type\RenameTagType;
14 15
15class TagController extends Controller 16class 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}