]> git.immae.eu Git - github/wallabag/wallabag.git/commitdiff
Add rss for entries
authorJeremy <jeremy.benoist@gmail.com>
Sat, 28 Mar 2015 13:27:45 +0000 (14:27 +0100)
committerJeremy <jeremy.benoist@gmail.com>
Tue, 31 Mar 2015 20:47:43 +0000 (22:47 +0200)
will fix #1000

13 files changed:
app/config/parameters.yml.dist
src/Wallabag/CoreBundle/Command/InstallCommand.php
src/Wallabag/CoreBundle/Controller/ConfigController.php
src/Wallabag/CoreBundle/Controller/RssController.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Entity/Config.php
src/Wallabag/CoreBundle/Entity/User.php
src/Wallabag/CoreBundle/Form/Type/RssType.php [new file with mode: 0644]
src/Wallabag/CoreBundle/ParamConverter/UsernameRssTokenConverter.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Repository/UserRepository.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Resources/config/services.yml
src/Wallabag/CoreBundle/Resources/views/Config/index.html.twig
src/Wallabag/CoreBundle/Resources/views/Entry/entries.xml.twig [new file with mode: 0644]
src/Wallabag/CoreBundle/Tools/Utils.php [new file with mode: 0644]

index 8f9670113c7b780547bfb9b11c9967287f57363e..7331801336fe005c139ff4c6544dab56726b9ecf 100644 (file)
@@ -42,3 +42,4 @@ parameters:
     theme: baggy
     language: en_US
     from_email: no-reply@wallabag.org
+    rss_limit: 50
index ac7583ea7f7d74770a9fca4761dd6ba207fa9f71..bba2607d05ae6c5ffd80585dbe268d2d97ffd98f 100644 (file)
@@ -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);
index 4e89587599c94b2f8750a9ebd2cc27868c73c0ac..1622f348262f762d255babb4dfce9c212dc73195 100644 (file)
@@ -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 (file)
index 0000000..f2f8dd6
--- /dev/null
@@ -0,0 +1,84 @@
+<?php
+
+namespace Wallabag\CoreBundle\Controller;
+
+use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
+use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
+use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+use Wallabag\CoreBundle\Entity\User;
+use Wallabag\CoreBundle\Entity\Entry;
+
+class RssController extends Controller
+{
+    /**
+     * Shows unread entries for current user
+     *
+     * @Route("/{username}/{token}/unread.xml", name="unread_rss", defaults={"_format"="xml"})
+     * @ParamConverter("user", class="WallabagCoreBundle:User", converter="username_rsstoken_converter")
+     *
+     * @return \Symfony\Component\HttpFoundation\Response
+     */
+    public function showUnreadAction(User $user)
+    {
+        $entries = $this->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,
+        ));
+    }
+}
index 91f9bfe82a4134ab4e3cc47bfcf290a5b8618c95..56eff30c5f48a202a467c41300c9c375bfb6874f 100644 (file)
@@ -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;
+    }
 }
index 6a7619ac2ab3addb7892966070cd1d7bd6b0745f..e75e3a8377bb21615ec7e93279f0c54ab306240e 100644 (file)
@@ -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 (file)
index 0000000..5edb38b
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+namespace Wallabag\CoreBundle\Form\Type;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolverInterface;
+
+class RssType extends AbstractType
+{
+    public function buildForm(FormBuilderInterface $builder, array $options)
+    {
+        $builder
+            ->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 (file)
index 0000000..ea2bda1
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+
+namespace Wallabag\CoreBundle\ParamConverter;
+
+use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface;
+use Doctrine\Common\Persistence\ManagerRegistry;
+use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Wallabag\CoreBundle\Entity\User;
+
+/**
+ * ParamConverter used in the RSS controller to retrieve the right user according to
+ * username & token given in the url.
+ *
+ * @see http://stfalcon.com/en/blog/post/symfony2-custom-paramconverter
+ */
+class UsernameRssTokenConverter implements ParamConverterInterface
+{
+    private $registry;
+
+    /**
+     * @param ManagerRegistry $registry Manager registry
+     */
+    public function __construct(ManagerRegistry $registry = null)
+    {
+        $this->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 (file)
index 0000000..aab3ded
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+
+namespace Wallabag\CoreBundle\Repository;
+
+use Doctrine\ORM\EntityRepository;
+
+class UserRepository extends EntityRepository
+{
+    /**
+     * Find a user by its username and rss roken
+     *
+     * @param string $username
+     * @param string $rssToken
+     *
+     * @return User|null
+     */
+    public function findOneByUsernameAndRsstoken($username, $rssToken)
+    {
+        return $this->createQueryBuilder('u')
+            ->leftJoin('u.config', 'c')
+            ->where('c.rssToken = :rss_token')->setParameter('rss_token', $rssToken)
+            ->andWhere('u.username = :username')->setParameter('username', $username)
+            ->getQuery()
+            ->getOneOrNullResult();
+    }
+}
index 062e1651fd7d2448a133048fc9ffc2cda385491c..0f4db94e7321791bdcd4f0f679bd040e5c19d43e 100644 (file)
@@ -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
index 1835d26e293edfc49e9303cc2ba4c9df8311fcca..b134b6ca24da863ae7480de024c4e96fdd873f1e 100644 (file)
 {% block content %}
     <h2>{% trans %}Wallabag configuration{% endtrans %}</h2>
 
-    <form action="{{ path('config') }}" method="post" {{ form_enctype(configForm) }}>
-        {{ form_errors(configForm) }}
+    <form action="{{ path('config') }}" method="post" {{ form_enctype(form.config) }}>
+        {{ form_errors(form.config) }}
 
         <fieldset class="w500p inline">
             <div class="row">
-                {{ 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) }}
             </div>
         </fieldset>
 
         <fieldset class="w500p inline">
             <div class="row">
-                {{ 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) }}
             </div>
         </fieldset>
 
         <fieldset class="w500p inline">
             <div class="row">
-                {{ 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) }}
             </div>
         </fieldset>
 
-        {{ form_rest(configForm) }}
+        {{ form_rest(form.config) }}
+    </form>
+
+    <h2>{% trans %}RSS configuration{% endtrans %}</h2>
+
+    <form action="{{ path('config') }}" method="post" {{ form_enctype(form.rss) }}>
+        {{ form_errors(form.rss) }}
+
+        <fieldset class="w500p inline">
+            <div class="row">
+                <label>Rss token</label>
+                {% if rss.token %}
+                    {{ rss.token }}
+                {% else %}
+                    <em>No token</em>
+                {% endif %}
+                –
+                <a href="{{ path('generate_token') }}">Regenerate ?</a>
+            </div>
+        </fieldset>
+
+        <fieldset class="w500p inline">
+            <div class="row">
+                <label>Rss links:</label>
+                <ul>
+                    <li><a href="{{ path('unread_rss', {'username': rss.username, 'token': rss.token}) }}">unread</a></li>
+                    <li><a href="{{ path('starred_rss', {'username': rss.username, 'token': rss.token}) }}">fav</a></li>
+                    <li><a href="{{ path('archive_rss', {'username': rss.username, 'token': rss.token}) }}">archives</a></li>
+                </ul>
+            </div>
+        </fieldset>
+
+        <fieldset class="w500p inline">
+            <div class="row">
+                {{ form_label(form.rss.rss_limit) }}
+                {{ form_errors(form.rss.rss_limit) }}
+                {{ form_widget(form.rss.rss_limit) }}
+            </div>
+        </fieldset>
+
+        {{ form_rest(form.rss) }}
     </form>
 
     <h2>{% trans %}User information{% endtrans %}</h2>
 
-    <form action="{{ path('config') }}" method="post" {{ form_enctype(userForm) }}>
-        {{ form_errors(userForm) }}
+    <form action="{{ path('config') }}" method="post" {{ form_enctype(form.user) }}>
+        {{ form_errors(form.user) }}
 
         <fieldset class="w500p inline">
             <div class="row">
-                {{ 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) }}
             </div>
         </fieldset>
 
         <fieldset class="w500p inline">
             <div class="row">
-                {{ 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) }}
             </div>
         </fieldset>
 
         <fieldset class="w500p inline">
             <div class="row">
-                {{ 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) }}
             </div>
         </fieldset>
 
-        {{ form_rest(userForm) }}
+        {{ form_rest(form.user) }}
     </form>
 
     <h2>{% trans %}Change your password{% endtrans %}</h2>
 
-    <form action="{{ path('config') }}" method="post" {{ form_enctype(pwdForm) }}>
-        {{ form_errors(pwdForm) }}
+    <form action="{{ path('config') }}" method="post" {{ form_enctype(form.pwd) }}>
+        {{ form_errors(form.pwd) }}
 
         <fieldset class="w500p inline">
             <div class="row">
-                {{ 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) }}
             </div>
         </fieldset>
 
         <fieldset class="w500p inline">
             <div class="row">
-                {{ 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) }}
             </div>
         </fieldset>
 
         <fieldset class="w500p inline">
             <div class="row">
-                {{ 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) }}
             </div>
         </fieldset>
 
-        {{ form_rest(pwdForm) }}
+        {{ form_rest(form.pwd) }}
     </form>
 
     <h2>{% trans %}Add a user{% endtrans %}</h2>
 
-    <form action="{{ path('config') }}" method="post" {{ form_enctype(newUserForm) }}>
-        {{ form_errors(newUserForm) }}
+    <form action="{{ path('config') }}" method="post" {{ form_enctype(form.new_user) }}>
+        {{ form_errors(form.new_user) }}
 
         <fieldset class="w500p inline">
             <div class="row">
-                {{ 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) }}
             </div>
         </fieldset>
 
         <fieldset class="w500p inline">
             <div class="row">
-                {{ 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) }}
             </div>
         </fieldset>
 
         <fieldset class="w500p inline">
             <div class="row">
-                {{ 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) }}
             </div>
         </fieldset>
 
-        {{ form_rest(newUserForm) }}
+        {{ form_rest(form.new_user) }}
     </form>
 {% 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 (file)
index 0000000..6eebc80
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">
+    <channel>
+        <title>wallabag — {{type}} feed</title>
+        <link>{{ url('unread') }}</link>
+        <pubDate>{{ "now"|date('D, d M Y H:i:s') }}</pubDate>
+        <generator>wallabag</generator>
+        <description>wallabag {{type}} elements</description>
+
+        {% for entry in entries %}
+
+            <item>
+                <title><![CDATA[{{ entry.title }}]]></title>
+                <source url="{{ url('view', { 'id': entry.id }) }}">wallabag</source>
+                <link>{{ url('view', { 'id': entry.id }) }}</link>
+                <guid>{{ url('view', { 'id': entry.id }) }}</guid>
+                <pubDate>{{ entry.createdAt|date('D, d M Y H:i:s') }}</pubDate>
+                <description>
+                    <![CDATA[
+                    {%- if entry.content| readingTime > 0 %}
+                        {% trans %}estimated reading time :{% endtrans %} {{ entry.content| readingTime }} min
+                    {% else -%}
+                        {% trans %}estimated reading time :{% endtrans %} &lt; 1 min
+                    {% endif -%}
+
+                    {{ entry.content -}}
+                    ]]>
+                </description>
+            </item>
+
+        {% endfor %}
+
+    </channel>
+</rss>
diff --git a/src/Wallabag/CoreBundle/Tools/Utils.php b/src/Wallabag/CoreBundle/Tools/Utils.php
new file mode 100644 (file)
index 0000000..de97c79
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+
+namespace Wallabag\CoreBundle\Tools;
+
+class Utils
+{
+    /**
+     * Generate a token used for RSS
+     *
+     * @return string
+     */
+    public static function generateToken()
+    {
+        if (ini_get('open_basedir') === '') {
+            if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
+                // alternative to /dev/urandom for Windows
+                $token = substr(base64_encode(uniqid(mt_rand(), true)), 0, 20);
+            } else {
+                $token = substr(base64_encode(file_get_contents('/dev/urandom', false, null, 0, 20)), 0, 15);
+            }
+        } else {
+            $token = substr(base64_encode(uniqid(mt_rand(), true)), 0, 20);
+        }
+
+        return str_replace('+', '', $token);
+    }
+}