]> git.immae.eu Git - github/wallabag/wallabag.git/commitdiff
Merge pull request #1095 from wallabag/v2-config
authorNicolas Lœuillet <nicolas@loeuillet.org>
Mon, 23 Feb 2015 19:56:09 +0000 (20:56 +0100)
committerNicolas Lœuillet <nicolas@loeuillet.org>
Mon, 23 Feb 2015 19:56:09 +0000 (20:56 +0100)
V2 config

33 files changed:
app/config/config.yml
app/config/global.inc.php [deleted file]
app/config/parameters.yml.dist
app/config/services.yml
src/Wallabag/CoreBundle/Command/InstallCommand.php
src/Wallabag/CoreBundle/Controller/ConfigController.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Controller/EntryController.php
src/Wallabag/CoreBundle/DataFixtures/ORM/LoadConfigData.php [new file with mode: 0644]
src/Wallabag/CoreBundle/DataFixtures/ORM/LoadEntryData.php
src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php
src/Wallabag/CoreBundle/Entity/Config.php
src/Wallabag/CoreBundle/Entity/User.php
src/Wallabag/CoreBundle/Entity/UsersConfig.php [deleted file]
src/Wallabag/CoreBundle/Form/Type/ChangePasswordType.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Form/Type/ConfigType.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Form/Type/EntryType.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Form/Type/NewUserType.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Form/Type/UserType.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Repository/ConfigRepository.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Resources/config/routing.yml
src/Wallabag/CoreBundle/Resources/views/Config/index.html.twig [new file with mode: 0644]
src/Wallabag/CoreBundle/Resources/views/_footer.html.twig
src/Wallabag/CoreBundle/Resources/views/_head.html.twig
src/Wallabag/CoreBundle/Resources/views/_menu.html.twig
src/Wallabag/CoreBundle/Resources/views/_search_form.html.twig
src/Wallabag/CoreBundle/Resources/views/_top.html.twig
src/Wallabag/CoreBundle/Security/Authentication/Encoder/WallabagPasswordEncoder.php
src/Wallabag/CoreBundle/Security/Validator/WallabagUserPasswordValidator.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Tests/Command/InstallCommandTest.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Tests/Controller/ConfigControllerTest.php [new file with mode: 0644]
src/Wallabag/CoreBundle/Tests/Controller/EntryControllerTest.php
src/Wallabag/CoreBundle/Tests/Controller/WallabagRestControllerTest.php
src/Wallabag/CoreBundle/Tests/WallabagTestCase.php

index 7dc1bf51fdec87e699088e197eb26084bbdd9000..33db245808c686cb2a97d8b871c0f6525e7fdf1f 100644 (file)
@@ -5,7 +5,7 @@ imports:
 
 framework:
     #esi:             ~
-    #translator:      { fallback: "%locale%" }
+    translator:      { fallback: "%locale%" }
     secret:          "%secret%"
     router:
         resource: "%kernel.root_dir%/config/routing.yml"
@@ -103,4 +103,4 @@ fos_rest:
     routing_loader:
         default_format: json
 
-nelmio_api_doc: ~
\ No newline at end of file
+nelmio_api_doc: ~
diff --git a/app/config/global.inc.php b/app/config/global.inc.php
deleted file mode 100755 (executable)
index 8e62818..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<?php
-/**
- * wallabag, self hostable application allowing you to not miss any content anymore
- *
- * @category   wallabag
- * @author     Nicolas Lœuillet <nicolas@loeuillet.org>
- * @copyright  2013
- * @license    http://opensource.org/licenses/MIT see COPYING file
- */
-
-define('ROOT', dirname(__FILE__) . '/../..');
-
-require_once ROOT . '/vendor/autoload.php';
-
-# system configuration
-require_once __DIR__ . '/config.inc.php';
-require_once __DIR__ . '/config.inc.default.php';
-
-if (!ini_get('date.timezone') || !@date_default_timezone_set(ini_get('date.timezone'))) {
-    date_default_timezone_set('UTC');
-}
-
-if (defined('ERROR_REPORTING')) {
-    error_reporting(ERROR_REPORTING);
-}
index e1be2e6e0462bf017df84315ebd1b16db6e90c78..449697505e1c13f5734c033515d25718c75397b0 100644 (file)
@@ -6,7 +6,7 @@ parameters:
     database_name: symfony
     database_user: root
     database_password: ~
-    database_path: "%kernel.root_dir%/../data/db/poche.sqlite"
+    database_path: "%kernel.root_dir%/../data/db/wallabag.sqlite"
 
     mailer_transport:  smtp
     mailer_host:       127.0.0.1
@@ -37,5 +37,7 @@ parameters:
     export_mobi: true
     export_pdf: true
 
-    # List view
-    items_on_page: 12
\ No newline at end of file
+    # default user config
+    items_on_page: 12
+    theme: baggy
+    language: en_US
index d4485e4290b20c672afdae4e53477ade0ea67508..91a03e10e13d5d03612c1e18a910db5e2143456a 100644 (file)
@@ -3,6 +3,7 @@
 parameters:
     security.authentication.provider.dao.class: Wallabag\CoreBundle\Security\Authentication\Provider\WallabagAuthenticationProvider
     security.encoder.digest.class: Wallabag\CoreBundle\Security\Authentication\Encoder\WallabagPasswordEncoder
+    security.validator.user_password.class: Wallabag\CoreBundle\Security\Validator\WallabagUserPasswordValidator
 
 services:
 #    service_name:
index feaaebf6903ac5e92758dd8ba3b04f7155bf83ba..ac7583ea7f7d74770a9fca4761dd6ba207fa9f71 100644 (file)
@@ -4,162 +4,308 @@ namespace Wallabag\CoreBundle\Command;
 
 use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
 use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Input\ArrayInput;
 use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Output\NullOutput;
 use Wallabag\CoreBundle\Entity\User;
-use Wallabag\CoreBundle\Entity\UsersConfig;
+use Wallabag\CoreBundle\Entity\Config;
 
 class InstallCommand extends ContainerAwareCommand
 {
+    /**
+     * @var InputInterface
+     */
+    protected $defaultInput;
+
+    /**
+     * @var OutputInterface
+     */
+    protected $defaultOutput;
+
     protected function configure()
     {
         $this
             ->setName('wallabag:install')
             ->setDescription('Wallabag installer.')
+            ->addOption(
+               'reset',
+               null,
+               InputOption::VALUE_NONE,
+               'Reset current database'
+            )
         ;
     }
 
     protected function execute(InputInterface $input, OutputInterface $output)
     {
-        $output->writeln('<info>Installing Wallabag.</info>');
+        $this->defaultInput = $input;
+        $this->defaultOutput = $output;
+
+        $output->writeln('<info>Installing Wallabag...</info>');
         $output->writeln('');
 
         $this
-            ->checkStep($output)
-            ->setupStep($input, $output)
+            ->checkRequirements()
+            ->setupDatabase()
+            ->setupAdmin()
+            ->setupAsset()
         ;
 
         $output->writeln('<info>Wallabag has been successfully installed.</info>');
         $output->writeln('<comment>Just execute `php app/console server:run` for using wallabag: http://localhost:8000</comment>');
     }
 
-    protected function checkStep(OutputInterface $output)
+    protected function checkRequirements()
     {
-        $output->writeln('<info>Checking system requirements.</info>');
+        $this->defaultOutput->writeln('<info><comment>Step 1 of 4.</comment> Checking system requirements.</info>');
 
         $fulfilled = true;
 
         // @TODO: find a better way to check requirements
-        $output->writeln('<comment>Check PCRE</comment>');
+        $label = '<comment>PCRE</comment>';
         if (extension_loaded('pcre')) {
-            $output->writeln(' <info>OK</info>');
+            $status = '<info>OK!</info>';
+            $help = '';
         } else {
             $fulfilled = false;
-            $output->writeln(' <error>ERROR</error>');
-            $output->writeln('<comment>You should enabled PCRE extension</comment>');
+            $status = '<error>ERROR!</error>';
+            $help = 'You should enabled PCRE extension';
         }
+        $rows[] = array($label, $status, $help);
 
-        $output->writeln('<comment>Check DOM</comment>');
+        $label = '<comment>DOM</comment>';
         if (extension_loaded('DOM')) {
-            $output->writeln(' <info>OK</info>');
+            $status = '<info>OK!</info>';
+            $help = '';
         } else {
             $fulfilled = false;
-            $output->writeln(' <error>ERROR</error>');
-            $output->writeln('<comment>You should enabled DOM extension</comment>');
+            $status = '<error>ERROR!</error>';
+            $help = 'You should enabled DOM extension';
         }
+        $rows[] = array($label, $status, $help);
+
+        $this->getHelper('table')
+            ->setHeaders(array('Checked', 'Status', 'Recommendation'))
+            ->setRows($rows)
+            ->render($this->defaultOutput);
 
         if (!$fulfilled) {
-            throw new RuntimeException('Some system requirements are not fulfilled. Please check output messages and fix them.');
+            throw new \RuntimeException('Some system requirements are not fulfilled. Please check output messages and fix them.');
+        } else {
+            $this->defaultOutput->writeln('<info>Success! Your system can run Wallabag properly.</info>');
         }
 
-        $output->writeln('');
+        $this->defaultOutput->writeln('');
 
         return $this;
     }
 
-    protected function setupStep(InputInterface $input, OutputInterface $output)
+    protected function setupDatabase()
     {
-        $output->writeln('<info>Setting up database.</info>');
+        $this->defaultOutput->writeln('<info><comment>Step 2 of 4.</comment> Setting up database.</info>');
 
-        $this->setupDatabase($input, $output);
+        // user want to reset everything? Don't care about what is already here
+        if (true === $this->defaultInput->getOption('reset')) {
+            $this->defaultOutput->writeln('Droping database, creating database and schema');
 
-        // if ($this->getHelperSet()->get('dialog')->askConfirmation($output, '<question>Load fixtures (Y/N)?</question>', false)) {
-        //     $this->setupFixtures($input, $output);
-        // }
+            $this
+                ->runCommand('doctrine:database:drop', array('--force' => true))
+                ->runCommand('doctrine:database:create')
+                ->runCommand('doctrine:schema:create')
+            ;
 
-        $output->writeln('');
-        $output->writeln('<info>Administration setup.</info>');
+            return $this;
+        }
 
-        $this->setupAdmin($output);
+        if (!$this->isDatabasePresent()) {
+            $this->defaultOutput->writeln('Creating database and schema, clearing the cache');
 
-        $output->writeln('');
+            $this
+                ->runCommand('doctrine:database:create')
+                ->runCommand('doctrine:schema:create')
+                ->runCommand('cache:clear')
+            ;
 
-        return $this;
-    }
+            return $this;
+        }
 
-    protected function setupDatabase(InputInterface $input, OutputInterface $output)
-    {
-        if ($this->getHelperSet()->get('dialog')->askConfirmation($output, '<question>Drop current database (Y/N)?</question>', true)) {
-            $connection = $this->getContainer()->get('doctrine')->getConnection();
-            $params = $connection->getParams();
+        $dialog = $this->getHelper('dialog');
 
-            $name = isset($params['path']) ? $params['path'] : (isset($params['dbname']) ? $params['dbname'] : false);
-            unset($params['dbname']);
+        if ($dialog->askConfirmation($this->defaultOutput, '<question>It appears that your database already exists. Would you like to reset it? (y/N)</question> ', false)) {
+            $this->defaultOutput->writeln('Droping database, creating database and schema');
 
-            if (!isset($params['path'])) {
-                $name = $connection->getDatabasePlatform()->quoteSingleIdentifier($name);
-            }
+            $this
+                ->runCommand('doctrine:database:drop', array('--force' => true))
+                ->runCommand('doctrine:database:create')
+                ->runCommand('doctrine:schema:create')
+            ;
+        } elseif ($this->isSchemaPresent()) {
+            if ($dialog->askConfirmation($this->defaultOutput, '<question>Seems like your database contains schema. Do you want to reset it? (y/N)</question> ', false)) {
+                $this->defaultOutput->writeln('Droping schema and creating schema');
 
-            $connection->getSchemaManager()->dropDatabase($name);
+                $this
+                    ->runCommand('doctrine:schema:drop', array('--force' => true))
+                    ->runCommand('doctrine:schema:create')
+                ;
+            }
         } else {
-            throw new \Exception("Install setup stopped, database need to be dropped. Please backup your current one and re-launch the install command.");
+            $this->defaultOutput->writeln('Creating schema');
+
+            $this
+                ->runCommand('doctrine:schema:create')
+            ;
         }
 
-        $this
-            ->runCommand('doctrine:database:create', $input, $output)
-            ->runCommand('doctrine:schema:create', $input, $output)
-            ->runCommand('cache:clear', $input, $output)
-            ->runCommand('assets:install', $input, $output)
-            ->runCommand('assetic:dump', $input, $output)
-        ;
-    }
+        $this->defaultOutput->writeln('Clearing the cache');
+        $this->runCommand('cache:clear');
+
+        /*
+        if ($this->getHelperSet()->get('dialog')->askConfirmation($this->defaultOutput, '<question>Load fixtures (Y/N)?</question>', false)) {
+            $doctrineConfig = $this->getContainer()->get('doctrine.orm.entity_manager')->getConnection()->getConfiguration();
+            $logger = $doctrineConfig->getSQLLogger();
+            // speed up fixture load
+            $doctrineConfig->setSQLLogger(null);
+            $this->runCommand('doctrine:fixtures:load');
+            $doctrineConfig->setSQLLogger($logger);
+        }
+        */
 
-    protected function setupFixtures(InputInterface $input, OutputInterface $output)
-    {
-        $doctrineConfig = $this->getContainer()->get('doctrine.orm.entity_manager')->getConnection()->getConfiguration();
-        $logger = $doctrineConfig->getSQLLogger();
-        // speed up fixture load
-        $doctrineConfig->setSQLLogger(null);
-        $this->runCommand('doctrine:fixtures:load', $input, $output);
-        $doctrineConfig->setSQLLogger($logger);
+        $this->defaultOutput->writeln('');
+
+        return $this;
     }
 
-    protected function setupAdmin(OutputInterface $output)
+    protected function setupAdmin()
     {
+        $this->defaultOutput->writeln('<info><comment>Step 3 of 4.</comment> Administration setup.</info>');
+
         $dialog = $this->getHelperSet()->get('dialog');
+
+        if (false === $dialog->askConfirmation($this->defaultOutput, '<question>Would you like to create a new user ? (y/N)</question>', true)) {
+            return $this;
+        }
+
         $em = $this->getContainer()->get('doctrine.orm.entity_manager');
 
         $user = new User();
-        $user->setUsername($dialog->ask($output, '<question>Username</question> <comment>(default: wallabag)</comment> :', 'wallabag'));
-        $user->setPassword($dialog->ask($output, '<question>Password</question> <comment>(default: wallabag)</comment> :', 'wallabag'));
-        $user->setEmail($dialog->ask($output, '<question>Email:</question>', ''));
+        $user->setUsername($dialog->ask($this->defaultOutput, '<question>Username</question> <comment>(default: wallabag)</comment> :', 'wallabag'));
+        $user->setPassword($dialog->ask($this->defaultOutput, '<question>Password</question> <comment>(default: wallabag)</comment> :', 'wallabag'));
+        $user->setEmail($dialog->ask($this->defaultOutput, '<question>Email:</question>', ''));
 
         $em->persist($user);
 
-        $pagerConfig = new UsersConfig();
-        $pagerConfig->setUserId($user->getId());
-        $pagerConfig->setName('pager');
-        $pagerConfig->setValue(10);
+        $config = new Config($user);
+        $config->setTheme($this->getContainer()->getParameter('theme'));
+        $config->setItemsPerPage($this->getContainer()->getParameter('items_on_page'));
+        $config->setLanguage($this->getContainer()->getParameter('language'));
 
-        $em->persist($pagerConfig);
+        $em->persist($config);
 
-        // $languageConfig = new LanguageConfig();
-        // $languageConfig->setUserId($user->getId());
-        // $languageConfig->setName('language');
-        // $languageConfig->setValue('en_EN.UTF8');
+        $em->flush();
 
-        // $em->persist($languageConfig);
+        $this->defaultOutput->writeln('');
 
-        $em->flush();
+        return $this;
     }
 
-    protected function runCommand($command, InputInterface $input, OutputInterface $output)
+    protected function setupAsset()
     {
+        $this->defaultOutput->writeln('<info><comment>Step 4 of 4.</comment> Installing assets.</info>');
+
         $this
-            ->getApplication()
-            ->find($command)
-            ->run($input, $output)
+            ->runCommand('assets:install')
+            ->runCommand('assetic:dump')
         ;
 
+        $this->defaultOutput->writeln('');
+
         return $this;
     }
+
+    /**
+     * Run a command
+     *
+     * @param string $command
+     * @param array  $parameters Parameters to this command (usually 'force' => true)
+     */
+    protected function runCommand($command, $parameters = array())
+    {
+        $parameters = array_merge(
+            array('command' => $command),
+            $parameters,
+            array(
+                '--no-debug' => true,
+                '--env' => $this->defaultInput->getOption('env') ?: 'dev',
+            )
+        );
+
+        if ($this->defaultInput->getOption('no-interaction')) {
+            $parameters = array_merge($parameters, array('--no-interaction' => true));
+        }
+
+        $this->getApplication()->setAutoExit(false);
+        $exitCode = $this->getApplication()->run(new ArrayInput($parameters), new NullOutput());
+
+        if (0 !== $exitCode) {
+            $this->getApplication()->setAutoExit(true);
+
+            $errorMessage = sprintf('The command "%s" terminated with an error code: %u.', $command, $exitCode);
+            $this->defaultOutput->writeln("<error>$errorMessage</error>");
+            $exception = new \Exception($errorMessage, $exitCode);
+
+            throw $exception;
+        }
+
+        // PDO does not always close the connection after Doctrine commands.
+        // See https://github.com/symfony/symfony/issues/11750.
+        $this->getContainer()->get('doctrine')->getManager()->getConnection()->close();
+
+        return $this;
+    }
+
+    /**
+     * Check if the database already exists
+     *
+     * @return boolean
+     */
+    private function isDatabasePresent()
+    {
+        $databaseName = $this->getContainer()->getParameter('database_name');
+
+        try {
+            $schemaManager = $this->getContainer()->get('doctrine')->getManager()->getConnection()->getSchemaManager();
+        } catch (\Exception $exception) {
+            if (false !== strpos($exception->getMessage(), sprintf("Unknown database '%s'", $databaseName))) {
+                return false;
+            }
+
+            throw $exception;
+        }
+
+        // custom verification for sqlite, since `getListDatabasesSQL` doesn't work for sqlite
+        if ('sqlite' == $schemaManager->getDatabasePlatform()->getName()) {
+            $params = $this->getContainer()->get('doctrine.dbal.default_connection')->getParams();
+
+            if (isset($params['path']) && file_exists($params['path'])) {
+                return true;
+            }
+
+            return false;
+        }
+
+        return in_array($databaseName, $schemaManager->listDatabases());
+    }
+
+    /**
+     * Check if the schema is already created
+     *
+     * @return boolean
+     */
+    private function isSchemaPresent()
+    {
+        $schemaManager = $this->getContainer()->get('doctrine')->getManager()->getConnection()->getSchemaManager();
+
+        return $schemaManager->tablesExist(array('entry'));
+    }
 }
diff --git a/src/Wallabag/CoreBundle/Controller/ConfigController.php b/src/Wallabag/CoreBundle/Controller/ConfigController.php
new file mode 100644 (file)
index 0000000..68e034f
--- /dev/null
@@ -0,0 +1,128 @@
+<?php
+
+namespace Wallabag\CoreBundle\Controller;
+
+use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
+use Symfony\Bundle\FrameworkBundle\Controller\Controller;
+use Symfony\Component\HttpFoundation\Request;
+use Wallabag\CoreBundle\Entity\Config;
+use Wallabag\CoreBundle\Entity\User;
+use Wallabag\CoreBundle\Form\Type\ConfigType;
+use Wallabag\CoreBundle\Form\Type\ChangePasswordType;
+use Wallabag\CoreBundle\Form\Type\UserType;
+use Wallabag\CoreBundle\Form\Type\NewUserType;
+
+class ConfigController extends Controller
+{
+    /**
+     * @param Request $request
+     *
+     * @Route("/config", name="config")
+     */
+    public function indexAction(Request $request)
+    {
+        $em = $this->getDoctrine()->getManager();
+        $config = $this->getConfig();
+        $user = $this->getUser();
+
+        // handle basic config detail
+        $configForm = $this->createForm(new ConfigType(), $config);
+        $configForm->handleRequest($request);
+
+        if ($configForm->isValid()) {
+            $em->persist($config);
+            $em->flush();
+
+            $this->get('session')->getFlashBag()->add(
+                'notice',
+                'Config saved'
+            );
+
+            return $this->redirect($this->generateUrl('config'));
+        }
+
+        // handle changing password
+        $pwdForm = $this->createForm(new ChangePasswordType());
+        $pwdForm->handleRequest($request);
+
+        if ($pwdForm->isValid()) {
+            $user->setPassword($pwdForm->get('new_password')->getData());
+            $em->persist($user);
+            $em->flush();
+
+            $this->get('session')->getFlashBag()->add(
+                'notice',
+                'Password updated'
+            );
+
+            return $this->redirect($this->generateUrl('config'));
+        }
+
+        // handle changing user information
+        $userForm = $this->createForm(new UserType(), $user);
+        $userForm->handleRequest($request);
+
+        if ($userForm->isValid()) {
+            $em->persist($user);
+            $em->flush();
+
+            $this->get('session')->getFlashBag()->add(
+                'notice',
+                'Information updated'
+            );
+
+            return $this->redirect($this->generateUrl('config'));
+        }
+
+        // handle adding new user
+        $newUser = new User();
+        $newUserForm = $this->createForm(new NewUserType(), $newUser);
+        $newUserForm->handleRequest($request);
+
+        if ($newUserForm->isValid()) {
+            $em->persist($newUser);
+
+            $config = new Config($newUser);
+            $config->setTheme($this->container->getParameter('theme'));
+            $config->setItemsPerPage($this->container->getParameter('items_on_page'));
+            $config->setLanguage($this->container->getParameter('language'));
+
+            $em->persist($config);
+
+            $em->flush();
+
+            $this->get('session')->getFlashBag()->add(
+                'notice',
+                sprintf('User "%s" added', $newUser->getUsername())
+            );
+
+            return $this->redirect($this->generateUrl('config'));
+        }
+
+        return $this->render('WallabagCoreBundle:Config:index.html.twig', array(
+            'configForm' => $configForm->createView(),
+            'pwdForm' => $pwdForm->createView(),
+            'userForm' => $userForm->createView(),
+            'newUserForm' => $newUserForm->createView(),
+        ));
+    }
+
+    /**
+     * Retrieve config for the current user.
+     * If no config were found, create a new one.
+     *
+     * @return Wallabag\CoreBundle\Entity\Config
+     */
+    private function getConfig()
+    {
+        $config = $this->getDoctrine()
+            ->getRepository('WallabagCoreBundle:Config')
+            ->findOneByUser($this->getUser());
+
+        if (!$config) {
+            $config = new Config($this->getUser());
+        }
+
+        return $config;
+    }
+}
index 89677befb6c347a003429513392254ee2fe1e00c..81ab77887af8596150b98e07ea424374afabf894 100644 (file)
@@ -7,7 +7,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
 use Symfony\Component\HttpFoundation\Request;
 use Wallabag\CoreBundle\Entity\Entry;
 use Wallabag\CoreBundle\Service\Extractor;
-use Wallabag\CoreBundle\Helper\Url;
+use Wallabag\CoreBundle\Form\Type\EntryType;
 
 class EntryController extends Controller
 {
@@ -22,10 +22,7 @@ class EntryController extends Controller
     {
         $entry = new Entry($this->getUser());
 
-        $form = $this->createFormBuilder($entry)
-            ->add('url', 'url')
-            ->add('save', 'submit')
-            ->getForm();
+        $form = $this->createForm(new EntryType(), $entry);
 
         $form->handleRequest($request);
 
diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadConfigData.php b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadConfigData.php
new file mode 100644 (file)
index 0000000..900e151
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+
+namespace Wallabag\CoreBundle\DataFixtures\ORM;
+
+use Doctrine\Common\DataFixtures\AbstractFixture;
+use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
+use Doctrine\Common\Persistence\ObjectManager;
+use Wallabag\CoreBundle\Entity\Config;
+
+class LoadConfigData extends AbstractFixture implements OrderedFixtureInterface
+{
+    /**
+     * {@inheritDoc}
+     */
+    public function load(ObjectManager $manager)
+    {
+        $adminConfig = new Config($this->getReference('admin-user'));
+        $adminConfig->setTheme('baggy');
+        $adminConfig->setItemsPerPage(30);
+        $adminConfig->setLanguage('en_US');
+
+        $manager->persist($adminConfig);
+
+        $this->addReference('admin-config', $adminConfig);
+
+        $bobConfig = new Config($this->getReference('bob-user'));
+        $bobConfig->setTheme('default');
+        $bobConfig->setItemsPerPage(10);
+        $bobConfig->setLanguage('fr_FR');
+
+        $manager->persist($bobConfig);
+
+        $this->addReference('bob-config', $bobConfig);
+
+        $manager->flush();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public function getOrder()
+    {
+        return 20;
+    }
+}
index 520b44b80921fd501c342e648edb2ffae40bf0dc..3be323ed7fc523756ccd9408276c30e576a49254 100644 (file)
@@ -49,6 +49,6 @@ class LoadEntryData extends AbstractFixture implements OrderedFixtureInterface
      */
     public function getOrder()
     {
-        return 20;
+        return 30;
     }
 }
index e4751f20206b09b353bc67272654b75f6002ef39..d99412f482e906f7be584716d5cee81e90c5f0a7 100644 (file)
@@ -18,7 +18,7 @@ class LoadUserData extends AbstractFixture implements OrderedFixtureInterface
         $userAdmin->setName('Big boss');
         $userAdmin->setEmail('bigboss@wallabag.org');
         $userAdmin->setUsername('admin');
-        $userAdmin->setPassword('test');
+        $userAdmin->setPassword('mypassword');
 
         $manager->persist($userAdmin);
 
@@ -28,7 +28,7 @@ class LoadUserData extends AbstractFixture implements OrderedFixtureInterface
         $bobUser->setName('Bobby');
         $bobUser->setEmail('bobby@wallabag.org');
         $bobUser->setUsername('bob');
-        $bobUser->setPassword('test');
+        $bobUser->setPassword('mypassword');
 
         $manager->persist($bobUser);
 
index 045ca308ee99991303ae0ecb95c3a0bc7f565cdf..7b4464a17cddc1374f8e779b9e6bbeb3a5ce9909 100644 (file)
@@ -3,10 +3,12 @@
 namespace Wallabag\CoreBundle\Entity;
 
 use Doctrine\ORM\Mapping as ORM;
+use Symfony\Component\Validator\Constraints as Assert;
 
 /**
  * Config
  *
+ * @ORM\Entity(repositoryClass="Wallabag\CoreBundle\Repository\ConfigRepository")
  * @ORM\Table(name="config")
  * @ORM\Entity
  */
@@ -15,25 +17,50 @@ class Config
     /**
      * @var integer
      *
-     * @ORM\Column(name="id", type="integer", nullable=false)
+     * @ORM\Column(name="id", type="integer")
      * @ORM\Id
-     * @ORM\GeneratedValue(strategy="IDENTITY")
+     * @ORM\GeneratedValue(strategy="AUTO")
      */
     private $id;
 
     /**
      * @var string
      *
-     * @ORM\Column(name="name", type="string", nullable=true)
+     * @Assert\NotBlank()
+     * @ORM\Column(name="theme", type="string", nullable=false)
      */
-    private $name;
+    private $theme;
 
     /**
      * @var string
      *
-     * @ORM\Column(name="value", type="blob", nullable=true)
+     * @Assert\NotBlank()
+     * @ORM\Column(name="items_per_page", type="integer", nullable=false)
      */
-    private $value;
+    private $items_per_page;
+
+    /**
+     * @var string
+     *
+     * @Assert\NotBlank()
+     * @ORM\Column(name="language", type="string", nullable=false)
+     */
+    private $language;
+
+    /**
+     * @ORM\ManyToOne(targetEntity="User", inversedBy="config")
+     */
+    private $user;
+
+    /*
+     * @param User     $user
+     */
+    public function __construct(User $user)
+    {
+        $this->user = $user;
+        $this->items_per_page = 12;
+        $this->language = 'en_US';
+    }
 
     /**
      * Get id
@@ -46,48 +73,94 @@ class Config
     }
 
     /**
-     * Set name
+     * Set theme
      *
-     * @param  string $name
+     * @param  string $theme
      * @return Config
      */
-    public function setName($name)
+    public function setTheme($theme)
     {
-        $this->name = $name;
+        $this->theme = $theme;
 
         return $this;
     }
 
     /**
-     * Get name
+     * Get theme
      *
      * @return string
      */
-    public function getName()
+    public function getTheme()
     {
-        return $this->name;
+        return $this->theme;
     }
 
     /**
-     * Set value
+     * Set items_per_page
      *
-     * @param  string $value
+     * @param  integer $itemsPerPage
      * @return Config
      */
-    public function setValue($value)
+    public function setItemsPerPage($itemsPerPage)
     {
-        $this->value = $value;
+        $this->items_per_page = $itemsPerPage;
 
         return $this;
     }
 
     /**
-     * Get value
+     * Get items_per_page
+     *
+     * @return integer
+     */
+    public function getItemsPerPage()
+    {
+        return $this->items_per_page;
+    }
+
+    /**
+     * Set language
+     *
+     * @param  string $language
+     * @return Config
+     */
+    public function setLanguage($language)
+    {
+        $this->language = $language;
+
+        return $this;
+    }
+
+    /**
+     * Get language
      *
      * @return string
      */
-    public function getValue()
+    public function getLanguage()
+    {
+        return $this->language;
+    }
+
+    /**
+     * Set user
+     *
+     * @param  \Wallabag\CoreBundle\Entity\User $user
+     * @return Config
+     */
+    public function setUser(\Wallabag\CoreBundle\Entity\User $user = null)
+    {
+        $this->user = $user;
+
+        return $this;
+    }
+
+    /**
+     * Get user
+     *
+     * @return \Wallabag\CoreBundle\Entity\User
+     */
+    public function getUser()
     {
-        return $this->value;
+        return $this->user;
     }
 }
index c83250c37e6d2a2bec25530c1a92667bc72904d1..193dfebc25bddfe7472f3dcfb07ee112ad84eb26 100644 (file)
@@ -6,6 +6,7 @@ use Doctrine\Common\Collections\ArrayCollection;
 use Doctrine\ORM\Mapping as ORM;
 use Symfony\Component\Security\Core\User\UserInterface;
 use Symfony\Component\Security\Core\User\AdvancedUserInterface;
+use Symfony\Component\Validator\Constraints as Assert;
 
 /**
  * User
@@ -29,6 +30,11 @@ class User implements AdvancedUserInterface, \Serializable
      * @var string
      *
      * @ORM\Column(name="username", type="text")
+     * @Assert\NotBlank()
+     * @Assert\Length(
+     *      min = "3",
+     *      max = "255"
+     * )
      */
     private $username;
 
@@ -56,14 +62,16 @@ class User implements AdvancedUserInterface, \Serializable
     /**
      * @var string
      *
-     * @ORM\Column(name="email", type="text", nullable=true)
+     * @ORM\Column(name="email", type="text", nullable=false)
+     * @Assert\Email()
+     * @Assert\NotBlank()
      */
     private $email;
 
     /**
-     * @ORM\Column(name="is_active", type="boolean")
+     * @ORM\Column(name="is_active", type="boolean", nullable=false)
      */
-    private $isActive;
+    private $isActive = true;
 
     /**
      * @var date
@@ -86,9 +94,8 @@ class User implements AdvancedUserInterface, \Serializable
 
     public function __construct()
     {
-        $this->isActive = true;
-        $this->salt     = md5(uniqid(null, true));
-        $this->entries  = new ArrayCollection();
+        $this->salt    = md5(uniqid(null, true));
+        $this->entries = new ArrayCollection();
     }
 
     /**
diff --git a/src/Wallabag/CoreBundle/Entity/UsersConfig.php b/src/Wallabag/CoreBundle/Entity/UsersConfig.php
deleted file mode 100644 (file)
index 0742edb..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-<?php
-
-namespace Wallabag\CoreBundle\Entity;
-
-use Doctrine\ORM\Mapping as ORM;
-
-/**
- * UsersConfig
- *
- * @ORM\Table(name="users_config")
- * @ORM\Entity
- */
-class UsersConfig
-{
-    /**
-     * @var integer
-     *
-     * @ORM\Column(name="id", type="integer", nullable=true)
-     * @ORM\Id
-     * @ORM\GeneratedValue(strategy="IDENTITY")
-     */
-    private $id;
-
-    /**
-     * @var string
-     *
-     * @ORM\Column(name="user_id", type="decimal", precision=10, scale=0, nullable=true)
-     */
-    private $userId;
-
-    /**
-     * @var string
-     *
-     * @ORM\Column(name="name", type="text", nullable=true)
-     */
-    private $name;
-
-    /**
-     * @var string
-     *
-     * @ORM\Column(name="value", type="text", nullable=true)
-     */
-    private $value;
-
-    /**
-     * Get id
-     *
-     * @return integer
-     */
-    public function getId()
-    {
-        return $this->id;
-    }
-
-    /**
-     * Set userId
-     *
-     * @param  string      $userId
-     * @return UsersConfig
-     */
-    public function setUserId($userId)
-    {
-        $this->userId = $userId;
-
-        return $this;
-    }
-
-    /**
-     * Get userId
-     *
-     * @return string
-     */
-    public function getUserId()
-    {
-        return $this->userId;
-    }
-
-    /**
-     * Set name
-     *
-     * @param  string      $name
-     * @return UsersConfig
-     */
-    public function setName($name)
-    {
-        $this->name = $name;
-
-        return $this;
-    }
-
-    /**
-     * Get name
-     *
-     * @return string
-     */
-    public function getName()
-    {
-        return $this->name;
-    }
-
-    /**
-     * Set value
-     *
-     * @param  string      $value
-     * @return UsersConfig
-     */
-    public function setValue($value)
-    {
-        $this->value = $value;
-
-        return $this;
-    }
-
-    /**
-     * Get value
-     *
-     * @return string
-     */
-    public function getValue()
-    {
-        return $this->value;
-    }
-}
diff --git a/src/Wallabag/CoreBundle/Form/Type/ChangePasswordType.php b/src/Wallabag/CoreBundle/Form/Type/ChangePasswordType.php
new file mode 100644 (file)
index 0000000..e141789
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+namespace Wallabag\CoreBundle\Form\Type;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\Security\Core\Validator\Constraints\UserPassword;
+use Symfony\Component\Validator\Constraints;
+
+class ChangePasswordType extends AbstractType
+{
+    public function buildForm(FormBuilderInterface $builder, array $options)
+    {
+        $builder
+            ->add('old_password', 'password', array(
+                'constraints' => new UserPassword(array('message' => 'Wrong value for your current password')),
+            ))
+            ->add('new_password', 'repeated', array(
+                'type' => 'password',
+                'invalid_message' => 'The password fields must match.',
+                'required' => true,
+                'first_options'  => array('label' => 'New password'),
+                'second_options' => array('label' => 'Repeat new password'),
+                'constraints' => array(
+                    new Constraints\Length(array(
+                        'min' => 8,
+                        'minMessage' => 'Password should by at least 8 chars long',
+                    )),
+                    new Constraints\NotBlank(),
+                ),
+            ))
+            ->add('save', 'submit')
+        ;
+    }
+
+    public function getName()
+    {
+        return 'change_passwd';
+    }
+}
diff --git a/src/Wallabag/CoreBundle/Form/Type/ConfigType.php b/src/Wallabag/CoreBundle/Form/Type/ConfigType.php
new file mode 100644 (file)
index 0000000..a1e0ce4
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+namespace Wallabag\CoreBundle\Form\Type;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolverInterface;
+
+class ConfigType extends AbstractType
+{
+    public function buildForm(FormBuilderInterface $builder, array $options)
+    {
+        $builder
+            ->add('theme', 'choice', array(
+                'choices' => array(
+                    'baggy' => 'Baggy',
+                    'courgette' => 'Courgette',
+                    'dark' => 'Dark',
+                    'default' => 'Default',
+                    'dmagenta' => 'Dmagenta',
+                    'solarized' => 'Solarized',
+                    'solarized_dark' => 'Solarized Dark',
+                ),
+            ))
+            ->add('items_per_page', 'text')
+            ->add('language')
+            ->add('save', 'submit')
+        ;
+    }
+
+    public function setDefaultOptions(OptionsResolverInterface $resolver)
+    {
+        $resolver->setDefaults(array(
+            'data_class' => 'Wallabag\CoreBundle\Entity\Config',
+        ));
+    }
+
+    public function getName()
+    {
+        return 'config';
+    }
+}
diff --git a/src/Wallabag/CoreBundle/Form/Type/EntryType.php b/src/Wallabag/CoreBundle/Form/Type/EntryType.php
new file mode 100644 (file)
index 0000000..cfd6447
--- /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 EntryType extends AbstractType
+{
+    public function buildForm(FormBuilderInterface $builder, array $options)
+    {
+        $builder
+            ->add('url', 'url')
+            ->add('save', 'submit')
+        ;
+    }
+
+    public function setDefaultOptions(OptionsResolverInterface $resolver)
+    {
+        $resolver->setDefaults(array(
+            'data_class' => 'Wallabag\CoreBundle\Entity\Entry',
+        ));
+    }
+
+    public function getName()
+    {
+        return 'entry';
+    }
+}
diff --git a/src/Wallabag/CoreBundle/Form/Type/NewUserType.php b/src/Wallabag/CoreBundle/Form/Type/NewUserType.php
new file mode 100644 (file)
index 0000000..313a9aa
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+namespace Wallabag\CoreBundle\Form\Type;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolverInterface;
+use Symfony\Component\Validator\Constraints;
+
+class NewUserType extends AbstractType
+{
+    public function buildForm(FormBuilderInterface $builder, array $options)
+    {
+        $builder
+            ->add('username', 'text')
+            ->add('password', 'password', array(
+                'constraints' => array(
+                    new Constraints\Length(array(
+                        'min' => 8,
+                        'minMessage' => 'Password should by at least 8 chars long',
+                    )),
+                    new Constraints\NotBlank(),
+                ),
+            ))
+            ->add('email', 'text')
+            ->add('save', 'submit')
+        ;
+    }
+
+    public function setDefaultOptions(OptionsResolverInterface $resolver)
+    {
+        $resolver->setDefaults(array(
+            'data_class' => 'Wallabag\CoreBundle\Entity\User',
+        ));
+    }
+
+    public function getName()
+    {
+        return 'new_user';
+    }
+}
diff --git a/src/Wallabag/CoreBundle/Form/Type/UserType.php b/src/Wallabag/CoreBundle/Form/Type/UserType.php
new file mode 100644 (file)
index 0000000..b479a0b
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+namespace Wallabag\CoreBundle\Form\Type;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolverInterface;
+
+class UserType extends AbstractType
+{
+    public function buildForm(FormBuilderInterface $builder, array $options)
+    {
+        $builder
+            ->add('username', 'text')
+            ->add('name', 'text')
+            ->add('email', 'text')
+            ->add('save', 'submit')
+        ;
+    }
+
+    public function setDefaultOptions(OptionsResolverInterface $resolver)
+    {
+        $resolver->setDefaults(array(
+            'data_class' => 'Wallabag\CoreBundle\Entity\User',
+        ));
+    }
+
+    public function getName()
+    {
+        return 'user';
+    }
+}
diff --git a/src/Wallabag/CoreBundle/Repository/ConfigRepository.php b/src/Wallabag/CoreBundle/Repository/ConfigRepository.php
new file mode 100644 (file)
index 0000000..b2b1f62
--- /dev/null
@@ -0,0 +1,9 @@
+<?php
+
+namespace Wallabag\CoreBundle\Repository;
+
+use Doctrine\ORM\EntityRepository;
+
+class ConfigRepository extends EntityRepository
+{
+}
index ec1d23cc9f6f0e0d7526e36bcfbfc73d9a6c46f2..f3502e156e6c80e884e9beb89bd42f76ec55bdd7 100644 (file)
@@ -1,3 +1,7 @@
-_wllbg:
+entry:
     resource: "@WallabagCoreBundle/Controller/EntryController.php"
     type:     annotation
+
+config:
+    resource: "@WallabagCoreBundle/Controller/ConfigController.php"
+    type:     annotation
diff --git a/src/Wallabag/CoreBundle/Resources/views/Config/index.html.twig b/src/Wallabag/CoreBundle/Resources/views/Config/index.html.twig
new file mode 100644 (file)
index 0000000..051dafd
--- /dev/null
@@ -0,0 +1,137 @@
+{% extends "WallabagCoreBundle::layout.html.twig" %}
+
+{% block title %}{% trans %}Config{% endtrans %}{% endblock %}
+
+{% block menu %}
+    {% include "WallabagCoreBundle::_menu.html.twig" %}
+{% endblock %}
+
+{% block content %}
+    <h2>{% trans %}Wallabag configuration{% endtrans %}</h2>
+
+    <form action="{{ path('config') }}" method="post" {{ form_enctype(configForm) }}>
+        {{ form_errors(configForm) }}
+
+        <fieldset class="w500p inline">
+            <div class="row">
+                {{ form_label(configForm.theme) }}
+                {{ form_errors(configForm.theme) }}
+                {{ form_widget(configForm.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) }}
+            </div>
+        </fieldset>
+
+        <fieldset class="w500p inline">
+            <div class="row">
+                {{ form_label(configForm.language) }}
+                {{ form_errors(configForm.language) }}
+                {{ form_widget(configForm.language) }}
+            </div>
+        </fieldset>
+
+        {{ form_rest(configForm) }}
+    </form>
+
+    <h2>{% trans %}User information{% endtrans %}</h2>
+
+    <form action="{{ path('config') }}" method="post" {{ form_enctype(userForm) }}>
+        {{ form_errors(userForm) }}
+
+        <fieldset class="w500p inline">
+            <div class="row">
+                {{ form_label(userForm.username) }}
+                {{ form_errors(userForm.username) }}
+                {{ form_widget(userForm.username) }}
+            </div>
+        </fieldset>
+
+        <fieldset class="w500p inline">
+            <div class="row">
+                {{ form_label(userForm.name) }}
+                {{ form_errors(userForm.name) }}
+                {{ form_widget(userForm.name) }}
+            </div>
+        </fieldset>
+
+        <fieldset class="w500p inline">
+            <div class="row">
+                {{ form_label(userForm.email) }}
+                {{ form_errors(userForm.email) }}
+                {{ form_widget(userForm.email) }}
+            </div>
+        </fieldset>
+
+        {{ form_rest(userForm) }}
+    </form>
+
+    <h2>{% trans %}Change your password{% endtrans %}</h2>
+
+    <form action="{{ path('config') }}" method="post" {{ form_enctype(pwdForm) }}>
+        {{ form_errors(pwdForm) }}
+
+        <fieldset class="w500p inline">
+            <div class="row">
+                {{ form_label(pwdForm.old_password) }}
+                {{ form_errors(pwdForm.old_password) }}
+                {{ form_widget(pwdForm.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) }}
+            </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) }}
+            </div>
+        </fieldset>
+
+        {{ form_rest(pwdForm) }}
+    </form>
+
+    <h2>{% trans %}Add a user{% endtrans %}</h2>
+
+    <form action="{{ path('config') }}" method="post" {{ form_enctype(newUserForm) }}>
+        {{ form_errors(newUserForm) }}
+
+        <fieldset class="w500p inline">
+            <div class="row">
+                {{ form_label(newUserForm.username) }}
+                {{ form_errors(newUserForm.username) }}
+                {{ form_widget(newUserForm.username) }}
+            </div>
+        </fieldset>
+
+        <fieldset class="w500p inline">
+            <div class="row">
+                {{ form_label(newUserForm.password) }}
+                {{ form_errors(newUserForm.password) }}
+                {{ form_widget(newUserForm.password) }}
+            </div>
+        </fieldset>
+
+        <fieldset class="w500p inline">
+            <div class="row">
+                {{ form_label(newUserForm.email) }}
+                {{ form_errors(newUserForm.email) }}
+                {{ form_widget(newUserForm.email) }}
+            </div>
+        </fieldset>
+
+        {{ form_rest(newUserForm) }}
+    </form>
+{% endblock %}
index 26411da9e4759451ca5918ffa5b9c5e91b4e199b..1b5f9a0fd6b7090bcb2707901817f9d5b33a6823 100644 (file)
@@ -1,3 +1,3 @@
-        <footer class="w600p center mt3 mb3 smaller txtright">
-            <p>{% trans %}powered by{% endtrans %} <a href="http://wallabag.org">wallabag</a></p>
-        </footer>
+<footer class="w600p center mt3 mb3 smaller txtright">
+    <p>{% trans %}powered by{% endtrans %} <a href="http://wallabag.org">wallabag</a></p>
+</footer>
index 726b4163a1836023f360d06b4921213f465387b3..3bdbe81244aa4808262977f22937aa4ef4c0eb91 100755 (executable)
@@ -1,40 +1,40 @@
-        <link rel="apple-touch-icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-152.png') }}" sizes="152x152">
-        <link rel="icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-152.png') }}" sizes="152x152">
+<link rel="apple-touch-icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-152.png') }}" sizes="152x152">
+<link rel="icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-152.png') }}" sizes="152x152">
 
-        <link rel="apple-touch-icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-144.png') }}" sizes="144x144">
-        <link rel="icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-144.png') }}" sizes="144x144">
+<link rel="apple-touch-icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-144.png') }}" sizes="144x144">
+<link rel="icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-144.png') }}" sizes="144x144">
 
-        <link rel="apple-touch-icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-120.png') }}" sizes="120x120">
-        <link rel="icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-120.png') }}" sizes="120x120">
+<link rel="apple-touch-icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-120.png') }}" sizes="120x120">
+<link rel="icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-120.png') }}" sizes="120x120">
 
-        <link rel="apple-touch-icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-114.png') }}" sizes="114x114">
-        <link rel="icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-114.png') }}" sizes="114x114">
+<link rel="apple-touch-icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-114.png') }}" sizes="114x114">
+<link rel="icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-114.png') }}" sizes="114x114">
 
-        <link rel="apple-touch-icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-76.png') }}" sizes="76x76">
-        <link rel="icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-76.png') }}" sizes="76x76">
+<link rel="apple-touch-icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-76.png') }}" sizes="76x76">
+<link rel="icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-76.png') }}" sizes="76x76">
 
-        <link rel="apple-touch-icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-72.png') }}" sizes="72x72">
-        <link rel="icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-72.png') }}" sizes="72x72">
+<link rel="apple-touch-icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-72.png') }}" sizes="72x72">
+<link rel="icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-72.png') }}" sizes="72x72">
 
-        <link rel="apple-touch-icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-57.png') }}" sizes="57x57">
-        <link rel="icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-57.png') }}" sizes="57x57">
+<link rel="apple-touch-icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-57.png') }}" sizes="57x57">
+<link rel="icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon-57.png') }}" sizes="57x57">
 
-        <link rel="apple-touch-icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon.png') }}">
-        <link rel="icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon.png') }}">
+<link rel="apple-touch-icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon.png') }}">
+<link rel="icon" type="image/png" href="{{ asset('themes/_global/img/appicon/apple-touch-icon.png') }}">
 
-        <link rel="shortcut icon" type="image/x-icon" href="{{ asset('themes/_global/img/appicon/favicon.ico') }}">
+<link rel="shortcut icon" type="image/x-icon" href="{{ asset('themes/_global/img/appicon/favicon.ico') }}">
 
-        <link rel="stylesheet" href="{{ asset('themes/baggy/css/ratatouille.css') }}" media="all">
-        <link rel="stylesheet" href="{{ asset('themes/baggy/css/font.css') }}" media="all">
-        <link rel="stylesheet" href="{{ asset('themes/baggy/css/main.css') }}" media="all">
-        <link rel="stylesheet" href="{{ asset('themes/baggy/css/messages.css') }}" media="all">
-        <link rel="stylesheet" href="{{ asset('themes/baggy/css/print.css') }}" media="print">
+<link rel="stylesheet" href="{{ asset('themes/baggy/css/ratatouille.css') }}" media="all">
+<link rel="stylesheet" href="{{ asset('themes/baggy/css/font.css') }}" media="all">
+<link rel="stylesheet" href="{{ asset('themes/baggy/css/main.css') }}" media="all">
+<link rel="stylesheet" href="{{ asset('themes/baggy/css/messages.css') }}" media="all">
+<link rel="stylesheet" href="{{ asset('themes/baggy/css/print.css') }}" media="print">
 
-        <script src="{{ asset('themes/_global/js/jquery-2.0.3.min.js') }}"></script>
-        <script src="{{ asset('themes/_global/js/autoClose.js') }}"></script>
-        <script src="{{ asset('themes/baggy/js/jquery.cookie.js') }}"></script>
-        <script src="{{ asset('themes/baggy/js/init.js') }}"></script>
-        <script src="{{ asset('themes/_global/js/saveLink.js') }}"></script>
-        <script src="{{ asset('themes/_global/js/popupForm.js') }}"></script>
-        <script src="{{ asset('themes/baggy/js/closeMessage.js') }}"></script>
-        <script src="{{ asset('bundles/wallabagcore/js/bookmarklet.js') }}"></script>
+<script src="{{ asset('themes/_global/js/jquery-2.0.3.min.js') }}"></script>
+<script src="{{ asset('themes/_global/js/autoClose.js') }}"></script>
+<script src="{{ asset('themes/baggy/js/jquery.cookie.js') }}"></script>
+<script src="{{ asset('themes/baggy/js/init.js') }}"></script>
+<script src="{{ asset('themes/_global/js/saveLink.js') }}"></script>
+<script src="{{ asset('themes/_global/js/popupForm.js') }}"></script>
+<script src="{{ asset('themes/baggy/js/closeMessage.js') }}"></script>
+<script src="{{ asset('bundles/wallabagcore/js/bookmarklet.js') }}"></script>
index 2e3b6d082a16efc20a38c203a254cb889e4ff7ef..9a3cf053e8197c2d8a3ab6f6c0d47cb6fa89a00a 100644 (file)
@@ -1,14 +1,14 @@
-            <button id="menu" class="icon icon-menu desktopHide"><span>Menu</span></button>
-            <ul id="links" class="links">
-                <li><a href="{{ path('unread') }}">{% trans %}unread{% endtrans %}</a></li>
-                <li><a href="{{ path('starred') }}">{% trans %}favorites{% endtrans %}</a></li>
-                <li><a href="{{ path('archive') }}"}>{% trans %}archive{% endtrans %}</a></li>
-                <li><a href="?view=tags">{% trans %}tags{% endtrans %}</a></li>
-                <li><a href="{{ path('new_entry') }}">{% trans %}save a link{% endtrans %}</a></li>
-                <li style="position: relative;"><a href="javascript: void(null);" id="search">{% trans %}search{% endtrans %}</a>
-                    {% include "WallabagCoreBundle::_search_form.html.twig" %}
-                </li>
-                <li><a href="?view=config">{% trans %}config{% endtrans %}</a></li>
-                <li><a href={{ path('about') }}>{% trans %}about{% endtrans %}</a></li>
-                <li><a class="icon icon-power" href="{{ path('logout') }}" title="{% trans %}logout{% endtrans %}">{% trans %}logout{% endtrans %}</a></li>
-            </ul>
+<button id="menu" class="icon icon-menu desktopHide"><span>Menu</span></button>
+<ul id="links" class="links">
+    <li><a href="{{ path('unread') }}">{% trans %}unread{% endtrans %}</a></li>
+    <li><a href="{{ path('starred') }}">{% trans %}favorites{% endtrans %}</a></li>
+    <li><a href="{{ path('archive') }}"}>{% trans %}archive{% endtrans %}</a></li>
+    <li><a href="?view=tags">{% trans %}tags{% endtrans %}</a></li>
+    <li><a href="{{ path('new_entry') }}">{% trans %}save a link{% endtrans %}</a></li>
+    <li style="position: relative;"><a href="javascript: void(null);" id="search">{% trans %}search{% endtrans %}</a>
+        {% include "WallabagCoreBundle::_search_form.html.twig" %}
+    </li>
+    <li><a href="{{ path('config') }}">{% trans %}config{% endtrans %}</a></li>
+    <li><a href="{{ path('about') }}">{% trans %}about{% endtrans %}</a></li>
+    <li><a class="icon icon-power" href="{{ path('logout') }}" title="{% trans %}logout{% endtrans %}">{% trans %}logout{% endtrans %}</a></li>
+</ul>
index 7eb1b67d8f472ea9473220f6061c5983ef1a33ab..1e6f327d23d13414f18fc78dc39aad2a97c6b4f6 100644 (file)
@@ -1,9 +1,9 @@
 <div id="search-form" class="messages info popup-form">
-<form method="get" action="index.php">
-       <h2>{% trans %}Search{% endtrans %}</h2>
+    <form method="get" action="index.php">
+        <h2>{% trans %}Search{% endtrans %}</h2>
         <a href="javascript: void(null);" id="search-form-close" class="close-button--popup close-button">&times;</a>
         <input type="hidden" name="view" value="search"></input>
         <input required placeholder="{% trans %}Enter your search here{% endtrans %}" type="text" name="search" id="searchfield"><br>
         <input id="submit-search" type="submit" value="{% trans %}Search{% endtrans %}"></input>
-</form>
+    </form>
 </div>
index 34d925df5d696e2369c65f10355c01ec6539e822..9313071dc1ed3e4695bcd854df4b97af4e801ad2 100755 (executable)
@@ -1,5 +1,5 @@
-        <header class="w600p center mbm">
-            <h1>
-                {% block logo %}<img width="100" height="100" src="{{ asset('themes/baggy/img/logo-w.png') }}" alt="wallabag logo" />{% endblock %}
-            </h1>
-        </header>
+<header class="w600p center mbm">
+    <h1>
+        {% block logo %}<img width="100" height="100" src="{{ asset('themes/baggy/img/logo-w.png') }}" alt="wallabag logo" />{% endblock %}
+    </h1>
+</header>
index 56f1affe32b8b6f615f07528b15037dd9f505db6..fcfe418bf966d076bb4c0e24f826010527ac47c8 100644 (file)
@@ -41,10 +41,6 @@ class WallabagPasswordEncoder extends BasePasswordEncoder
      */
     public function encodePassword($raw, $salt)
     {
-        if (null === $this->username) {
-            throw new \LogicException('We can not check the password without a username.');
-        }
-
         if ($this->isPasswordTooLong($raw)) {
             throw new BadCredentialsException('Invalid password.');
         }
@@ -71,6 +67,10 @@ class WallabagPasswordEncoder extends BasePasswordEncoder
      */
     protected function mergePasswordAndSalt($password, $salt)
     {
+        if (null === $this->username) {
+            throw new \LogicException('We can not check the password without a username.');
+        }
+
         if (empty($salt)) {
             return $password;
         }
diff --git a/src/Wallabag/CoreBundle/Security/Validator/WallabagUserPasswordValidator.php b/src/Wallabag/CoreBundle/Security/Validator/WallabagUserPasswordValidator.php
new file mode 100644 (file)
index 0000000..5586f97
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+
+namespace Wallabag\CoreBundle\Security\Validator;
+
+use Symfony\Component\Security\Core\User\UserInterface;
+use Symfony\Component\Security\Core\SecurityContextInterface;
+use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
+use Symfony\Component\Validator\Constraint;
+use Symfony\Component\Validator\ConstraintValidator;
+use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
+use Symfony\Component\Validator\Exception\UnexpectedTypeException;
+use Symfony\Component\Security\Core\Validator\Constraints\UserPassword;
+
+class WallabagUserPasswordValidator extends ConstraintValidator
+{
+    private $securityContext;
+    private $encoderFactory;
+
+    public function __construct(SecurityContextInterface $securityContext, EncoderFactoryInterface $encoderFactory)
+    {
+        $this->securityContext = $securityContext;
+        $this->encoderFactory = $encoderFactory;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function validate($password, Constraint $constraint)
+    {
+        if (!$constraint instanceof UserPassword) {
+            throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\UserPassword');
+        }
+
+        $user = $this->securityContext->getToken()->getUser();
+
+        if (!$user instanceof UserInterface) {
+            throw new ConstraintDefinitionException('The User object must implement the UserInterface interface.');
+        }
+
+        // give username, it's used to hash the password
+        $encoder = $this->encoderFactory->getEncoder($user);
+        $encoder->setUsername($user->getUsername());
+
+        if (!$encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt())) {
+            $this->context->addViolation($constraint->message);
+        }
+    }
+}
diff --git a/src/Wallabag/CoreBundle/Tests/Command/InstallCommandTest.php b/src/Wallabag/CoreBundle/Tests/Command/InstallCommandTest.php
new file mode 100644 (file)
index 0000000..64f6c32
--- /dev/null
@@ -0,0 +1,274 @@
+<?php
+
+namespace Wallabag\CoreBundle\Tests\Command;
+
+use Wallabag\CoreBundle\Tests\WallabagTestCase;
+use Wallabag\CoreBundle\Command\InstallCommand;
+use Symfony\Bundle\FrameworkBundle\Console\Application;
+use Symfony\Component\Console\Tester\CommandTester;
+use Symfony\Component\Console\Input\ArrayInput;
+use Symfony\Component\Console\Output\NullOutput;
+use Doctrine\Bundle\DoctrineBundle\Command\DropDatabaseDoctrineCommand;
+use Doctrine\Bundle\DoctrineBundle\Command\CreateDatabaseDoctrineCommand;
+
+class InstallCommandTest extends WallabagTestCase
+{
+    public static function tearDownAfterClass()
+    {
+        $application = new Application(static::$kernel);
+        $application->setAutoExit(false);
+
+        $code = $application->run(new ArrayInput(array(
+            'command' => 'doctrine:fixtures:load',
+            '--no-interaction' => true,
+            '--env' => 'test',
+        )), new NullOutput());
+    }
+
+    public function testRunInstallCommand()
+    {
+        $this->container = static::$kernel->getContainer();
+
+        $application = new Application(static::$kernel);
+        $application->add(new InstallCommand());
+
+        $command = $application->find('wallabag:install');
+
+        // We mock the DialogHelper
+        $dialog = $this->getMockBuilder('Symfony\Component\Console\Helper\DialogHelper')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $dialog->expects($this->any())
+            ->method('ask')
+            ->will($this->returnValue('test'));
+        $dialog->expects($this->any())
+            ->method('askConfirmation')
+            ->will($this->returnValue(true));
+
+        // We override the standard helper with our mock
+        $command->getHelperSet()->set($dialog, 'dialog');
+
+        $tester = new CommandTester($command);
+        $tester->execute(array(
+            'command' => $command->getName(),
+        ));
+
+        $this->assertContains('Step 1 of 4. Checking system requirements.', $tester->getDisplay());
+        $this->assertContains('Step 2 of 4. Setting up database.', $tester->getDisplay());
+        $this->assertContains('Step 3 of 4. Administration setup.', $tester->getDisplay());
+        $this->assertContains('Step 4 of 4. Installing assets.', $tester->getDisplay());
+    }
+
+    public function testRunInstallCommandWithReset()
+    {
+        $this->container = static::$kernel->getContainer();
+
+        $application = new Application(static::$kernel);
+        $application->add(new InstallCommand());
+
+        $command = $application->find('wallabag:install');
+
+        // We mock the DialogHelper
+        $dialog = $this->getMockBuilder('Symfony\Component\Console\Helper\DialogHelper')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $dialog->expects($this->any())
+            ->method('ask')
+            ->will($this->returnValue('test'));
+        $dialog->expects($this->any())
+            ->method('askConfirmation')
+            ->will($this->returnValue(true));
+
+        // We override the standard helper with our mock
+        $command->getHelperSet()->set($dialog, 'dialog');
+
+        $tester = new CommandTester($command);
+        $tester->execute(array(
+            'command' => $command->getName(),
+            '--reset' => true,
+        ));
+
+        $this->assertContains('Step 1 of 4. Checking system requirements.', $tester->getDisplay());
+        $this->assertContains('Step 2 of 4. Setting up database.', $tester->getDisplay());
+        $this->assertContains('Step 3 of 4. Administration setup.', $tester->getDisplay());
+        $this->assertContains('Step 4 of 4. Installing assets.', $tester->getDisplay());
+
+        // we force to reset everything
+        $this->assertContains('Droping database, creating database and schema', $tester->getDisplay());
+    }
+
+    public function testRunInstallCommandWithDatabaseRemoved()
+    {
+        $this->container = static::$kernel->getContainer();
+
+        $application = new Application(static::$kernel);
+        $application->add(new InstallCommand());
+        $application->add(new DropDatabaseDoctrineCommand());
+
+        // drop database first, so the install command won't ask to reset things
+        $command = new DropDatabaseDoctrineCommand();
+        $command->setApplication($application);
+        $command->run(new ArrayInput(array(
+            'command' => 'doctrine:database:drop',
+            '--force' => true,
+        )), new NullOutput());
+
+        $command = $application->find('wallabag:install');
+
+        // We mock the DialogHelper
+        $dialog = $this->getMockBuilder('Symfony\Component\Console\Helper\DialogHelper')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $dialog->expects($this->any())
+            ->method('ask')
+            ->will($this->returnValue('test'));
+        $dialog->expects($this->any())
+            ->method('askConfirmation')
+            ->will($this->returnValue(true));
+
+        // We override the standard helper with our mock
+        $command->getHelperSet()->set($dialog, 'dialog');
+
+        $tester = new CommandTester($command);
+        $tester->execute(array(
+            'command' => $command->getName(),
+        ));
+
+        $this->assertContains('Step 1 of 4. Checking system requirements.', $tester->getDisplay());
+        $this->assertContains('Step 2 of 4. Setting up database.', $tester->getDisplay());
+        $this->assertContains('Step 3 of 4. Administration setup.', $tester->getDisplay());
+        $this->assertContains('Step 4 of 4. Installing assets.', $tester->getDisplay());
+
+        // the current database doesn't already exist
+        $this->assertContains('Creating database and schema, clearing the cache', $tester->getDisplay());
+    }
+
+    public function testRunInstallCommandChooseResetSchema()
+    {
+        $this->container = static::$kernel->getContainer();
+
+        $application = new Application(static::$kernel);
+        $application->add(new InstallCommand());
+
+        $command = $application->find('wallabag:install');
+
+        // We mock the DialogHelper
+        $dialog = $this->getMockBuilder('Symfony\Component\Console\Helper\DialogHelper')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $dialog->expects($this->exactly(3))
+            ->method('askConfirmation')
+            ->will($this->onConsecutiveCalls(
+                false, // don't want to reset the entire database
+                true, // do want to reset the schema
+                false // don't want to create a new user
+            ));
+
+        // We override the standard helper with our mock
+        $command->getHelperSet()->set($dialog, 'dialog');
+
+        $tester = new CommandTester($command);
+        $tester->execute(array(
+            'command' => $command->getName(),
+        ));
+
+        $this->assertContains('Step 1 of 4. Checking system requirements.', $tester->getDisplay());
+        $this->assertContains('Step 2 of 4. Setting up database.', $tester->getDisplay());
+        $this->assertContains('Step 3 of 4. Administration setup.', $tester->getDisplay());
+        $this->assertContains('Step 4 of 4. Installing assets.', $tester->getDisplay());
+
+        $this->assertContains('Droping schema and creating schema', $tester->getDisplay());
+    }
+
+    public function testRunInstallCommandChooseNothing()
+    {
+        $this->container = static::$kernel->getContainer();
+
+        $application = new Application(static::$kernel);
+        $application->add(new InstallCommand());
+        $application->add(new DropDatabaseDoctrineCommand());
+        $application->add(new CreateDatabaseDoctrineCommand());
+
+        // drop database first, so the install command won't ask to reset things
+        $command = new DropDatabaseDoctrineCommand();
+        $command->setApplication($application);
+        $command->run(new ArrayInput(array(
+            'command' => 'doctrine:database:drop',
+            '--force' => true,
+        )), new NullOutput());
+
+        $this->container->get('doctrine')->getManager()->getConnection()->close();
+
+        $command = new CreateDatabaseDoctrineCommand();
+        $command->setApplication($application);
+        $command->run(new ArrayInput(array(
+            'command' => 'doctrine:database:create',
+            '--env' => 'test',
+        )), new NullOutput());
+
+        $command = $application->find('wallabag:install');
+
+        // We mock the DialogHelper
+        $dialog = $this->getMockBuilder('Symfony\Component\Console\Helper\DialogHelper')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $dialog->expects($this->exactly(2))
+            ->method('askConfirmation')
+            ->will($this->onConsecutiveCalls(
+                false, // don't want to reset the entire database
+                false // don't want to create a new user
+            ));
+
+        // We override the standard helper with our mock
+        $command->getHelperSet()->set($dialog, 'dialog');
+
+        $tester = new CommandTester($command);
+        $tester->execute(array(
+            'command' => $command->getName(),
+        ));
+
+        $this->assertContains('Step 1 of 4. Checking system requirements.', $tester->getDisplay());
+        $this->assertContains('Step 2 of 4. Setting up database.', $tester->getDisplay());
+        $this->assertContains('Step 3 of 4. Administration setup.', $tester->getDisplay());
+        $this->assertContains('Step 4 of 4. Installing assets.', $tester->getDisplay());
+
+        $this->assertContains('Creating schema', $tester->getDisplay());
+    }
+
+    public function testRunInstallCommandNoInteraction()
+    {
+        $this->container = static::$kernel->getContainer();
+
+        $application = new Application(static::$kernel);
+        $application->add(new InstallCommand());
+
+        $command = $application->find('wallabag:install');
+
+        // We mock the DialogHelper
+        $dialog = $this->getMockBuilder('Symfony\Component\Console\Helper\DialogHelper')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $dialog->expects($this->any())
+            ->method('ask')
+            ->will($this->returnValue('test'));
+        $dialog->expects($this->any())
+            ->method('askConfirmation')
+            ->will($this->returnValue(true));
+
+        // We override the standard helper with our mock
+        $command->getHelperSet()->set($dialog, 'dialog');
+
+        $tester = new CommandTester($command);
+        $tester->execute(array(
+            'command' => $command->getName(),
+            '--no-interaction' => true,
+        ));
+
+        $this->assertContains('Step 1 of 4. Checking system requirements.', $tester->getDisplay());
+        $this->assertContains('Step 2 of 4. Setting up database.', $tester->getDisplay());
+        $this->assertContains('Step 3 of 4. Administration setup.', $tester->getDisplay());
+        $this->assertContains('Step 4 of 4. Installing assets.', $tester->getDisplay());
+    }
+}
diff --git a/src/Wallabag/CoreBundle/Tests/Controller/ConfigControllerTest.php b/src/Wallabag/CoreBundle/Tests/Controller/ConfigControllerTest.php
new file mode 100644 (file)
index 0000000..9b1a098
--- /dev/null
@@ -0,0 +1,350 @@
+<?php
+
+namespace Wallabag\CoreBundle\Tests\Controller;
+
+use Wallabag\CoreBundle\Tests\WallabagTestCase;
+
+class ConfigControllerTest extends WallabagTestCase
+{
+    public function testLogin()
+    {
+        $client = $this->getClient();
+
+        $client->request('GET', '/new');
+
+        $this->assertEquals(302, $client->getResponse()->getStatusCode());
+        $this->assertContains('login', $client->getResponse()->headers->get('location'));
+    }
+
+    public function testIndex()
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+
+        $crawler = $client->request('GET', '/config');
+
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+
+        $this->assertCount(1, $crawler->filter('button[id=config_save]'));
+        $this->assertCount(1, $crawler->filter('button[id=change_passwd_save]'));
+        $this->assertCount(1, $crawler->filter('button[id=user_save]'));
+    }
+
+    public function testUpdate()
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+
+        $crawler = $client->request('GET', '/config');
+
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+
+        $form = $crawler->filter('button[id=config_save]')->form();
+
+        $data = array(
+            'config[theme]' => 'baggy',
+            'config[items_per_page]' => '30',
+            'config[language]' => 'fr_FR',
+        );
+
+        $client->submit($form, $data);
+
+        $this->assertEquals(302, $client->getResponse()->getStatusCode());
+
+        $crawler = $client->followRedirect();
+
+        $this->assertGreaterThan(1, $alert = $crawler->filter('div.flash-notice')->extract(array('_text')));
+        $this->assertContains('Config saved', $alert[0]);
+    }
+
+    public function dataForUpdateFailed()
+    {
+        return array(
+            array(array(
+                'config[theme]' => 'baggy',
+                'config[items_per_page]' => '',
+                'config[language]' => 'fr_FR',
+            )),
+            array(array(
+                'config[theme]' => 'baggy',
+                'config[items_per_page]' => '12',
+                'config[language]' => '',
+            )),
+        );
+    }
+
+    /**
+     * @dataProvider dataForUpdateFailed
+     */
+    public function testUpdateFailed($data)
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+
+        $crawler = $client->request('GET', '/config');
+
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+
+        $form = $crawler->filter('button[id=config_save]')->form();
+
+        $crawler = $client->submit($form, $data);
+
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+
+        $this->assertGreaterThan(1, $alert = $crawler->filter('body')->extract(array('_text')));
+        $this->assertContains('This value should not be blank', $alert[0]);
+    }
+
+    public function dataForChangePasswordFailed()
+    {
+        return array(
+            array(
+                array(
+                    'change_passwd[old_password]' => 'baggy',
+                    'change_passwd[new_password][first]' => '',
+                    'change_passwd[new_password][second]' => '',
+                ),
+                'Wrong value for your current password',
+            ),
+            array(
+                array(
+                    'change_passwd[old_password]' => 'mypassword',
+                    'change_passwd[new_password][first]' => '',
+                    'change_passwd[new_password][second]' => '',
+                ),
+                'This value should not be blank',
+            ),
+            array(
+                array(
+                    'change_passwd[old_password]' => 'mypassword',
+                    'change_passwd[new_password][first]' => 'hop',
+                    'change_passwd[new_password][second]' => '',
+                ),
+                'The password fields must match',
+            ),
+            array(
+                array(
+                    'change_passwd[old_password]' => 'mypassword',
+                    'change_passwd[new_password][first]' => 'hop',
+                    'change_passwd[new_password][second]' => 'hop',
+                ),
+                'Password should by at least',
+            ),
+        );
+    }
+
+    /**
+     * @dataProvider dataForChangePasswordFailed
+     */
+    public function testChangePasswordFailed($data, $expectedMessage)
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+
+        $crawler = $client->request('GET', '/config');
+
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+
+        $form = $crawler->filter('button[id=change_passwd_save]')->form();
+
+        $crawler = $client->submit($form, $data);
+
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+
+        $this->assertGreaterThan(1, $alert = $crawler->filter('body')->extract(array('_text')));
+        $this->assertContains($expectedMessage, $alert[0]);
+    }
+
+    public function testChangePassword()
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+
+        $crawler = $client->request('GET', '/config');
+
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+
+        $form = $crawler->filter('button[id=change_passwd_save]')->form();
+
+        $data = array(
+            'change_passwd[old_password]' => 'mypassword',
+            'change_passwd[new_password][first]' => 'mypassword',
+            'change_passwd[new_password][second]' => 'mypassword',
+        );
+
+        $client->submit($form, $data);
+
+        $this->assertEquals(302, $client->getResponse()->getStatusCode());
+
+        $crawler = $client->followRedirect();
+
+        $this->assertGreaterThan(1, $alert = $crawler->filter('div.flash-notice')->extract(array('_text')));
+        $this->assertContains('Password updated', $alert[0]);
+    }
+
+    public function dataForUserFailed()
+    {
+        return array(
+            array(
+                array(
+                    'user[username]' => '',
+                    'user[name]' => '',
+                    'user[email]' => '',
+                ),
+                'This value should not be blank.',
+            ),
+            array(
+                array(
+                    'user[username]' => 'ad',
+                    'user[name]' => '',
+                    'user[email]' => '',
+                ),
+                'This value is too short.',
+            ),
+            array(
+                array(
+                    'user[username]' => 'admin',
+                    'user[name]' => '',
+                    'user[email]' => 'test',
+                ),
+                'This value is not a valid email address.',
+            ),
+        );
+    }
+
+    /**
+     * @dataProvider dataForUserFailed
+     */
+    public function testUserFailed($data, $expectedMessage)
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+
+        $crawler = $client->request('GET', '/config');
+
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+
+        $form = $crawler->filter('button[id=user_save]')->form();
+
+        $crawler = $client->submit($form, $data);
+
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+
+        $this->assertGreaterThan(1, $alert = $crawler->filter('body')->extract(array('_text')));
+        $this->assertContains($expectedMessage, $alert[0]);
+    }
+
+    public function testUserUpdate()
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+
+        $crawler = $client->request('GET', '/config');
+
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+
+        $form = $crawler->filter('button[id=user_save]')->form();
+
+        $data = array(
+            'user[username]' => 'admin',
+            'user[name]' => 'new name',
+            'user[email]' => 'admin@wallabag.io',
+        );
+
+        $client->submit($form, $data);
+
+        $this->assertEquals(302, $client->getResponse()->getStatusCode());
+
+        $crawler = $client->followRedirect();
+
+        $this->assertGreaterThan(1, $alert = $crawler->filter('div.flash-notice')->extract(array('_text')));
+        $this->assertContains('Information updated', $alert[0]);
+    }
+
+    public function dataForNewUserFailed()
+    {
+        return array(
+            array(
+                array(
+                    'new_user[username]' => '',
+                    'new_user[password]' => '',
+                    'new_user[email]' => '',
+                ),
+                'This value should not be blank.',
+            ),
+            array(
+                array(
+                    'new_user[username]' => 'ad',
+                    'new_user[password]' => '',
+                    'new_user[email]' => '',
+                ),
+                'This value is too short.',
+            ),
+            array(
+                array(
+                    'new_user[username]' => 'wallace',
+                    'new_user[password]' => '',
+                    'new_user[email]' => 'test',
+                ),
+                'This value is not a valid email address.',
+            ),
+            array(
+                array(
+                    'new_user[username]' => 'wallace',
+                    'new_user[password]' => 'admin',
+                    'new_user[email]' => 'wallace@wallace.me',
+                ),
+                'Password should by at least',
+            ),
+        );
+    }
+
+    /**
+     * @dataProvider dataForNewUserFailed
+     */
+    public function testNewUserFailed($data, $expectedMessage)
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+
+        $crawler = $client->request('GET', '/config');
+
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+
+        $form = $crawler->filter('button[id=new_user_save]')->form();
+
+        $crawler = $client->submit($form, $data);
+
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+
+        $this->assertGreaterThan(1, $alert = $crawler->filter('body')->extract(array('_text')));
+        $this->assertContains($expectedMessage, $alert[0]);
+    }
+
+    public function testNewUserCreated()
+    {
+        $this->logInAs('admin');
+        $client = $this->getClient();
+
+        $crawler = $client->request('GET', '/config');
+
+        $this->assertEquals(200, $client->getResponse()->getStatusCode());
+
+        $form = $crawler->filter('button[id=new_user_save]')->form();
+
+        $data = array(
+            'new_user[username]' => 'wallace',
+            'new_user[password]' => 'wallace1',
+            'new_user[email]' => 'wallace@wallace.me',
+        );
+
+        $client->submit($form, $data);
+
+        $this->assertEquals(302, $client->getResponse()->getStatusCode());
+
+        $crawler = $client->followRedirect();
+
+        $this->assertGreaterThan(1, $alert = $crawler->filter('div.flash-notice')->extract(array('_text')));
+        $this->assertContains('User "wallace" added', $alert[0]);
+    }
+}
index 7276f8e4ecba5ec57b80d84a096d23fb9eff1671..2634141e504aa832945942252d3d46801a469f7f 100644 (file)
@@ -60,7 +60,7 @@ class EntryControllerTest extends WallabagTestCase
         $form = $crawler->filter('button[type=submit]')->form();
 
         $data = array(
-            'form[url]' => 'https://www.mailjet.com/blog/mailjet-zapier-integrations-made-easy/',
+            'entry[url]' => 'https://www.mailjet.com/blog/mailjet-zapier-integrations-made-easy/',
         );
 
         $client->submit($form, $data);
index d77e23037edfd5491e93f0774e494bd0146f3dd4..fcfa8ccf9a233aa69eb310312f61d5c0805d6ad3 100644 (file)
@@ -47,7 +47,7 @@ class WallabagRestControllerTest extends WallabagTestCase
         $client->request('GET', '/api/salts/admin.json');
         $salt = json_decode($client->getResponse()->getContent());
 
-        $headers = $this->generateHeaders('admin', 'test', $salt[0]);
+        $headers = $this->generateHeaders('admin', 'mypassword', $salt[0]);
 
         $entry = $client->getContainer()
             ->get('doctrine.orm.entity_manager')
@@ -73,7 +73,7 @@ class WallabagRestControllerTest extends WallabagTestCase
         $client->request('GET', '/api/salts/admin.json');
         $salt = json_decode($client->getResponse()->getContent());
 
-        $headers = $this->generateHeaders('admin', 'test', $salt[0]);
+        $headers = $this->generateHeaders('admin', 'mypassword', $salt[0]);
 
         $entry = $client->getContainer()
             ->get('doctrine.orm.entity_manager')
@@ -101,7 +101,7 @@ class WallabagRestControllerTest extends WallabagTestCase
         $client->request('GET', '/api/salts/admin.json');
         $salt = json_decode($client->getResponse()->getContent());
 
-        $headers = $this->generateHeaders('admin', 'test', $salt[0]);
+        $headers = $this->generateHeaders('admin', 'mypassword', $salt[0]);
 
         $client->request('GET', '/api/entries', array(), array(), $headers);
 
@@ -125,7 +125,7 @@ class WallabagRestControllerTest extends WallabagTestCase
         $client->request('GET', '/api/salts/admin.json');
         $salt = json_decode($client->getResponse()->getContent());
 
-        $headers = $this->generateHeaders('admin', 'test', $salt[0]);
+        $headers = $this->generateHeaders('admin', 'mypassword', $salt[0]);
 
         $entry = $client->getContainer()
             ->get('doctrine.orm.entity_manager')
index a80b8bac426e2093dbdc2ebdec926424851e5eae..22016d8edd7c04727c416a7bf8a9faa338693200 100644 (file)
@@ -4,7 +4,7 @@ namespace Wallabag\CoreBundle\Tests;
 
 use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
 
-class WallabagTestCase extends WebTestCase
+abstract class WallabagTestCase extends WebTestCase
 {
     private $client = null;
 
@@ -24,7 +24,7 @@ class WallabagTestCase extends WebTestCase
         $form = $crawler->filter('button[type=submit]')->form();
         $data = array(
             '_username' => $username,
-            '_password' => 'test',
+            '_password' => 'mypassword',
         );
 
         $this->client->submit($form, $data);