From 0c83fd5994861efa728097dd151c994796c39ae1 Mon Sep 17 00:00:00 2001 From: Jeremy Date: Sat, 28 Mar 2015 14:27:45 +0100 Subject: [PATCH] Add rss for entries will fix #1000 --- app/config/parameters.yml.dist | 1 + .../CoreBundle/Command/InstallCommand.php | 1 + .../Controller/ConfigController.php | 58 +++++++- .../CoreBundle/Controller/RssController.php | 84 +++++++++++ src/Wallabag/CoreBundle/Entity/Config.php | 74 ++++++++-- src/Wallabag/CoreBundle/Entity/User.php | 2 +- src/Wallabag/CoreBundle/Form/Type/RssType.php | 29 ++++ .../UsernameRssTokenConverter.php | 92 ++++++++++++ .../CoreBundle/Repository/UserRepository.php | 26 ++++ .../CoreBundle/Resources/config/services.yml | 7 + .../Resources/views/Config/index.html.twig | 136 +++++++++++------- .../Resources/views/Entry/entries.xml.twig | 34 +++++ src/Wallabag/CoreBundle/Tools/Utils.php | 27 ++++ 13 files changed, 510 insertions(+), 61 deletions(-) create mode 100644 src/Wallabag/CoreBundle/Controller/RssController.php create mode 100644 src/Wallabag/CoreBundle/Form/Type/RssType.php create mode 100644 src/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverter.php create mode 100644 src/Wallabag/CoreBundle/Repository/UserRepository.php create mode 100644 src/Wallabag/CoreBundle/Resources/views/Entry/entries.xml.twig create mode 100644 src/Wallabag/CoreBundle/Tools/Utils.php diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist index 8f967011..73318013 100644 --- a/app/config/parameters.yml.dist +++ b/app/config/parameters.yml.dist @@ -42,3 +42,4 @@ parameters: theme: baggy language: en_US from_email: no-reply@wallabag.org + rss_limit: 50 diff --git a/src/Wallabag/CoreBundle/Command/InstallCommand.php b/src/Wallabag/CoreBundle/Command/InstallCommand.php index ac7583ea..bba2607d 100644 --- a/src/Wallabag/CoreBundle/Command/InstallCommand.php +++ b/src/Wallabag/CoreBundle/Command/InstallCommand.php @@ -198,6 +198,7 @@ class InstallCommand extends ContainerAwareCommand $config = new Config($user); $config->setTheme($this->getContainer()->getParameter('theme')); $config->setItemsPerPage($this->getContainer()->getParameter('items_on_page')); + $config->setRssLimit($this->getContainer()->getParameter('rss_limit')); $config->setLanguage($this->getContainer()->getParameter('language')); $em->persist($config); diff --git a/src/Wallabag/CoreBundle/Controller/ConfigController.php b/src/Wallabag/CoreBundle/Controller/ConfigController.php index 4e895875..1622f348 100644 --- a/src/Wallabag/CoreBundle/Controller/ConfigController.php +++ b/src/Wallabag/CoreBundle/Controller/ConfigController.php @@ -5,11 +5,14 @@ namespace Wallabag\CoreBundle\Controller; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\JsonResponse; use Wallabag\CoreBundle\Entity\Config; use Wallabag\CoreBundle\Entity\User; use Wallabag\CoreBundle\Form\Type\ChangePasswordType; use Wallabag\CoreBundle\Form\Type\UserType; use Wallabag\CoreBundle\Form\Type\NewUserType; +use Wallabag\CoreBundle\Form\Type\RssType; +use Wallabag\CoreBundle\Tools\Utils; class ConfigController extends Controller { @@ -77,6 +80,22 @@ class ConfigController extends Controller return $this->redirect($this->generateUrl('config')); } + // handle rss information + $rssForm = $this->createForm(new RssType(), $config); + $rssForm->handleRequest($request); + + if ($rssForm->isValid()) { + $em->persist($config); + $em->flush(); + + $this->get('session')->getFlashBag()->add( + 'notice', + 'RSS information updated' + ); + + return $this->redirect($this->generateUrl('config')); + } + // handle adding new user $newUser = new User(); $newUserForm = $this->createForm(new NewUserType(), $newUser); @@ -88,6 +107,7 @@ class ConfigController extends Controller $config = new Config($newUser); $config->setTheme($this->container->getParameter('theme')); $config->setItemsPerPage($this->container->getParameter('items_on_page')); + $config->setRssLimit($this->getContainer()->getParameter('rss_limit')); $config->setLanguage($this->container->getParameter('language')); $em->persist($config); @@ -103,13 +123,43 @@ class ConfigController extends Controller } return $this->render('WallabagCoreBundle:Config:index.html.twig', array( - 'configForm' => $configForm->createView(), - 'pwdForm' => $pwdForm->createView(), - 'userForm' => $userForm->createView(), - 'newUserForm' => $newUserForm->createView(), + 'form' => array( + 'config' => $configForm->createView(), + 'rss' => $rssForm->createView(), + 'pwd' => $pwdForm->createView(), + 'user' => $userForm->createView(), + 'new_user' => $newUserForm->createView(), + ), + 'rss' => array( + 'username' => $user->getUsername(), + 'token' => $config->getRssToken(), + ) )); } + /** + * @param Request $request + * + * @Route("/generate-token", name="generate_token") + * + * @return JsonResponse + */ + public function generateTokenAction(Request $request) + { + $config = $this->getConfig(); + $config->setRssToken(Utils::generateToken()); + + $em = $this->getDoctrine()->getManager(); + $em->persist($config); + $em->flush(); + + if ($request->isXmlHttpRequest()) { + return new JsonResponse(array('token' => $config->getRssToken())); + } + + return $request->headers->get('referer') ? $this->redirect($request->headers->get('referer')) : $this->redirectToRoute('config'); + } + /** * Retrieve config for the current user. * If no config were found, create a new one. diff --git a/src/Wallabag/CoreBundle/Controller/RssController.php b/src/Wallabag/CoreBundle/Controller/RssController.php new file mode 100644 index 00000000..f2f8dd65 --- /dev/null +++ b/src/Wallabag/CoreBundle/Controller/RssController.php @@ -0,0 +1,84 @@ +getDoctrine() + ->getRepository('WallabagCoreBundle:Entry') + ->findUnreadByUser( + $user->getId(), + 0, + $user->getConfig()->getRssLimit() ?: $this->getContainer()->getParameter('rss_limit') + ); + + return $this->render('WallabagCoreBundle:Entry:entries.xml.twig', array( + 'type' => 'unread', + 'entries' => $entries, + )); + } + + /** + * Shows read entries for current user + * + * @Route("/{username}/{token}/archive.xml", name="archive_rss") + * @ParamConverter("user", class="WallabagCoreBundle:User", converter="username_rsstoken_converter") + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function showArchiveAction(User $user) + { + $entries = $this->getDoctrine() + ->getRepository('WallabagCoreBundle:Entry') + ->findArchiveByUser( + $user->getId(), + 0, + $user->getConfig()->getRssLimit() ?: $this->getContainer()->getParameter('rss_limit') + ); + + return $this->render('WallabagCoreBundle:Entry:entries.xml.twig', array( + 'type' => 'archive', + 'entries' => $entries, + )); + } + + /** + * Shows starred entries for current user + * + * @Route("/{username}/{token}/starred.xml", name="starred_rss") + * @ParamConverter("user", class="WallabagCoreBundle:User", converter="username_rsstoken_converter") + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function showStarredAction(User $user) + { + $entries = $this->getDoctrine() + ->getRepository('WallabagCoreBundle:Entry') + ->findStarredByUser( + $user->getId(), + 0, + $user->getConfig()->getRssLimit() ?: $this->getContainer()->getParameter('rss_limit') + ); + + return $this->render('WallabagCoreBundle:Entry:entries.xml.twig', array( + 'type' => 'starred', + 'entries' => $entries, + )); + } +} diff --git a/src/Wallabag/CoreBundle/Entity/Config.php b/src/Wallabag/CoreBundle/Entity/Config.php index 91f9bfe8..56eff30c 100644 --- a/src/Wallabag/CoreBundle/Entity/Config.php +++ b/src/Wallabag/CoreBundle/Entity/Config.php @@ -32,12 +32,12 @@ class Config private $theme; /** - * @var string + * @var integer * * @Assert\NotBlank() * @ORM\Column(name="items_per_page", type="integer", nullable=false) */ - private $items_per_page; + private $itemsPerPage; /** * @var string @@ -47,6 +47,20 @@ class Config */ private $language; + /** + * @var string + * + * @ORM\Column(name="rss_token", type="string", nullable=true) + */ + private $rssToken; + + /** + * @var integer + * + * @ORM\Column(name="rss_limit", type="integer", nullable=true) + */ + private $rssLimit; + /** * @ORM\OneToOne(targetEntity="User", inversedBy="config") */ @@ -58,8 +72,6 @@ class Config public function __construct(User $user) { $this->user = $user; - $this->items_per_page = 12; - $this->language = 'en_US'; } /** @@ -96,26 +108,26 @@ class Config } /** - * Set items_per_page + * Set itemsPerPage * * @param integer $itemsPerPage * @return Config */ public function setItemsPerPage($itemsPerPage) { - $this->items_per_page = $itemsPerPage; + $this->itemsPerPage = $itemsPerPage; return $this; } /** - * Get items_per_page + * Get itemsPerPage * * @return integer */ public function getItemsPerPage() { - return $this->items_per_page; + return $this->itemsPerPage; } /** @@ -163,4 +175,50 @@ class Config { return $this->user; } + + /** + * Set rssToken + * + * @param string $rssToken + * @return Config + */ + public function setRssToken($rssToken) + { + $this->rssToken = $rssToken; + + return $this; + } + + /** + * Get rssToken + * + * @return string + */ + public function getRssToken() + { + return $this->rssToken; + } + + /** + * Set rssLimit + * + * @param string $rssLimit + * @return Config + */ + public function setRssLimit($rssLimit) + { + $this->rssLimit = $rssLimit; + + return $this; + } + + /** + * Get rssLimit + * + * @return string + */ + public function getRssLimit() + { + return $this->rssLimit; + } } diff --git a/src/Wallabag/CoreBundle/Entity/User.php b/src/Wallabag/CoreBundle/Entity/User.php index 6a7619ac..e75e3a83 100644 --- a/src/Wallabag/CoreBundle/Entity/User.php +++ b/src/Wallabag/CoreBundle/Entity/User.php @@ -14,7 +14,7 @@ use JMS\Serializer\Annotation\Expose; * User * * @ORM\Table(name="user") - * @ORM\Entity + * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\UserRepository") * @ORM\HasLifecycleCallbacks() * @ExclusionPolicy("all") */ diff --git a/src/Wallabag/CoreBundle/Form/Type/RssType.php b/src/Wallabag/CoreBundle/Form/Type/RssType.php new file mode 100644 index 00000000..5edb38ba --- /dev/null +++ b/src/Wallabag/CoreBundle/Form/Type/RssType.php @@ -0,0 +1,29 @@ +add('rss_limit', 'text') + ->add('save', 'submit') + ; + } + + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'data_class' => 'Wallabag\CoreBundle\Entity\Config', + )); + } + + public function getName() + { + return 'rss_config'; + } +} diff --git a/src/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverter.php b/src/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverter.php new file mode 100644 index 00000000..ea2bda17 --- /dev/null +++ b/src/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverter.php @@ -0,0 +1,92 @@ +registry = $registry; + } + + /** + * {@inheritdoc} + * + * Check, if object supported by our converter + */ + public function supports(ParamConverter $configuration) + { + // If there is no manager, this means that only Doctrine DBAL is configured + // In this case we can do nothing and just return + if (null === $this->registry || !count($this->registry->getManagers())) { + return false; + } + + // Check, if option class was set in configuration + if (null === $configuration->getClass()) { + return false; + } + + // Get actual entity manager for class + $em = $this->registry->getManagerForClass($configuration->getClass()); + + // Check, if class name is what we need + if ('Wallabag\CoreBundle\Entity\User' !== $em->getClassMetadata($configuration->getClass())->getName()) { + return false; + } + + return true; + } + + /** + * {@inheritdoc} + * + * Applies converting + * + * @throws \InvalidArgumentException When route attributes are missing + * @throws NotFoundHttpException When object not found + */ + public function apply(Request $request, ParamConverter $configuration) + { + $username = $request->attributes->get('username'); + $rssToken = $request->attributes->get('token'); + + // Check, if route attributes exists + if (null === $username || null === $rssToken) { + throw new \InvalidArgumentException('Route attribute is missing'); + } + + // Get actual entity manager for class + $em = $this->registry->getManagerForClass($configuration->getClass()); + + $userRepository = $em->getRepository($configuration->getClass()); + + // Try to find user by its username and config rss_token + $user = $userRepository->findOneByUsernameAndRsstoken($username, $rssToken); + + if (null === $user || !($user instanceof User)) { + throw new NotFoundHttpException(sprintf('%s not found.', $configuration->getClass())); + } + + // Map found user to the route's parameter + $request->attributes->set($configuration->getName(), $user); + } +} diff --git a/src/Wallabag/CoreBundle/Repository/UserRepository.php b/src/Wallabag/CoreBundle/Repository/UserRepository.php new file mode 100644 index 00000000..aab3dedc --- /dev/null +++ b/src/Wallabag/CoreBundle/Repository/UserRepository.php @@ -0,0 +1,26 @@ +createQueryBuilder('u') + ->leftJoin('u.config', 'c') + ->where('c.rssToken = :rss_token')->setParameter('rss_token', $rssToken) + ->andWhere('u.username = :username')->setParameter('username', $username) + ->getQuery() + ->getOneOrNullResult(); + } +} diff --git a/src/Wallabag/CoreBundle/Resources/config/services.yml b/src/Wallabag/CoreBundle/Resources/config/services.yml index 062e1651..0f4db94e 100644 --- a/src/Wallabag/CoreBundle/Resources/config/services.yml +++ b/src/Wallabag/CoreBundle/Resources/config/services.yml @@ -36,3 +36,10 @@ services: - @doctrine tags: - { name: form.type, alias: forgot_password } + + wallabag_core.param_converter.username_rsstoken_converter: + class: Wallabag\CoreBundle\ParamConverter\UsernameRssTokenConverter + tags: + - { name: request.param_converter, converter: username_rsstoken_converter } + arguments: + - @doctrine diff --git a/src/Wallabag/CoreBundle/Resources/views/Config/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/Config/index.html.twig index 1835d26e..b134b6ca 100644 --- a/src/Wallabag/CoreBundle/Resources/views/Config/index.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/Config/index.html.twig @@ -5,129 +5,169 @@ {% block content %}

{% trans %}Wallabag configuration{% endtrans %}

-
- {{ form_errors(configForm) }} + + {{ form_errors(form.config) }}
- {{ form_label(configForm.theme) }} - {{ form_errors(configForm.theme) }} - {{ form_widget(configForm.theme) }} + {{ form_label(form.config.theme) }} + {{ form_errors(form.config.theme) }} + {{ form_widget(form.config.theme) }}
- {{ form_label(configForm.items_per_page) }} - {{ form_errors(configForm.items_per_page) }} - {{ form_widget(configForm.items_per_page) }} + {{ form_label(form.config.items_per_page) }} + {{ form_errors(form.config.items_per_page) }} + {{ form_widget(form.config.items_per_page) }}
- {{ form_label(configForm.language) }} - {{ form_errors(configForm.language) }} - {{ form_widget(configForm.language) }} + {{ form_label(form.config.language) }} + {{ form_errors(form.config.language) }} + {{ form_widget(form.config.language) }}
- {{ form_rest(configForm) }} + {{ form_rest(form.config) }} +
+ +

{% trans %}RSS configuration{% endtrans %}

+ +
+ {{ form_errors(form.rss) }} + +
+
+ + {% if rss.token %} + {{ rss.token }} + {% else %} + No token + {% endif %} + – + Regenerate ? +
+
+ +
+
+ + +
+
+ +
+
+ {{ form_label(form.rss.rss_limit) }} + {{ form_errors(form.rss.rss_limit) }} + {{ form_widget(form.rss.rss_limit) }} +
+
+ + {{ form_rest(form.rss) }}

{% trans %}User information{% endtrans %}

-
- {{ form_errors(userForm) }} + + {{ form_errors(form.user) }}
- {{ form_label(userForm.username) }} - {{ form_errors(userForm.username) }} - {{ form_widget(userForm.username) }} + {{ form_label(form.user.username) }} + {{ form_errors(form.user.username) }} + {{ form_widget(form.user.username) }}
- {{ form_label(userForm.name) }} - {{ form_errors(userForm.name) }} - {{ form_widget(userForm.name) }} + {{ form_label(form.user.name) }} + {{ form_errors(form.user.name) }} + {{ form_widget(form.user.name) }}
- {{ form_label(userForm.email) }} - {{ form_errors(userForm.email) }} - {{ form_widget(userForm.email) }} + {{ form_label(form.user.email) }} + {{ form_errors(form.user.email) }} + {{ form_widget(form.user.email) }}
- {{ form_rest(userForm) }} + {{ form_rest(form.user) }}

{% trans %}Change your password{% endtrans %}

-
- {{ form_errors(pwdForm) }} + + {{ form_errors(form.pwd) }}
- {{ form_label(pwdForm.old_password) }} - {{ form_errors(pwdForm.old_password) }} - {{ form_widget(pwdForm.old_password) }} + {{ form_label(form.pwd.old_password) }} + {{ form_errors(form.pwd.old_password) }} + {{ form_widget(form.pwd.old_password) }}
- {{ form_label(pwdForm.new_password.first) }} - {{ form_errors(pwdForm.new_password.first) }} - {{ form_widget(pwdForm.new_password.first) }} + {{ form_label(form.pwd.new_password.first) }} + {{ form_errors(form.pwd.new_password.first) }} + {{ form_widget(form.pwd.new_password.first) }}
- {{ form_label(pwdForm.new_password.second) }} - {{ form_errors(pwdForm.new_password.second) }} - {{ form_widget(pwdForm.new_password.second) }} + {{ form_label(form.pwd.new_password.second) }} + {{ form_errors(form.pwd.new_password.second) }} + {{ form_widget(form.pwd.new_password.second) }}
- {{ form_rest(pwdForm) }} + {{ form_rest(form.pwd) }}

{% trans %}Add a user{% endtrans %}

-
- {{ form_errors(newUserForm) }} + + {{ form_errors(form.new_user) }}
- {{ form_label(newUserForm.username) }} - {{ form_errors(newUserForm.username) }} - {{ form_widget(newUserForm.username) }} + {{ form_label(form.new_user.username) }} + {{ form_errors(form.new_user.username) }} + {{ form_widget(form.new_user.username) }}
- {{ form_label(newUserForm.password) }} - {{ form_errors(newUserForm.password) }} - {{ form_widget(newUserForm.password) }} + {{ form_label(form.new_user.password) }} + {{ form_errors(form.new_user.password) }} + {{ form_widget(form.new_user.password) }}
- {{ form_label(newUserForm.email) }} - {{ form_errors(newUserForm.email) }} - {{ form_widget(newUserForm.email) }} + {{ form_label(form.new_user.email) }} + {{ form_errors(form.new_user.email) }} + {{ form_widget(form.new_user.email) }}
- {{ form_rest(newUserForm) }} + {{ form_rest(form.new_user) }}
{% endblock %} diff --git a/src/Wallabag/CoreBundle/Resources/views/Entry/entries.xml.twig b/src/Wallabag/CoreBundle/Resources/views/Entry/entries.xml.twig new file mode 100644 index 00000000..6eebc80d --- /dev/null +++ b/src/Wallabag/CoreBundle/Resources/views/Entry/entries.xml.twig @@ -0,0 +1,34 @@ + + + + wallabag — {{type}} feed + {{ url('unread') }} + {{ "now"|date('D, d M Y H:i:s') }} + wallabag + wallabag {{type}} elements + + {% for entry in entries %} + + + <![CDATA[{{ entry.title }}]]> + wallabag + {{ url('view', { 'id': entry.id }) }} + {{ url('view', { 'id': entry.id }) }} + {{ entry.createdAt|date('D, d M Y H:i:s') }} + + 0 %} + {% trans %}estimated reading time :{% endtrans %} {{ entry.content| readingTime }} min + {% else -%} + {% trans %}estimated reading time :{% endtrans %} < 1 min + {% endif -%} + + {{ entry.content -}} + ]]> + + + + {% endfor %} + + + diff --git a/src/Wallabag/CoreBundle/Tools/Utils.php b/src/Wallabag/CoreBundle/Tools/Utils.php new file mode 100644 index 00000000..de97c796 --- /dev/null +++ b/src/Wallabag/CoreBundle/Tools/Utils.php @@ -0,0 +1,27 @@ +