diff --git a/app/config/config.yml b/app/config/config.yml index 7dc1bf51f..33db24580 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -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 index 8e62818ba..000000000 --- a/app/config/global.inc.php +++ /dev/null @@ -1,25 +0,0 @@ - - * @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); -} diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist index e1be2e6e0..449697505 100644 --- a/app/config/parameters.yml.dist +++ b/app/config/parameters.yml.dist @@ -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 diff --git a/app/config/services.yml b/app/config/services.yml index d4485e429..91a03e10e 100644 --- a/app/config/services.yml +++ b/app/config/services.yml @@ -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: diff --git a/src/Wallabag/CoreBundle/Command/InstallCommand.php b/src/Wallabag/CoreBundle/Command/InstallCommand.php index feaaebf69..ac7583ea7 100644 --- a/src/Wallabag/CoreBundle/Command/InstallCommand.php +++ b/src/Wallabag/CoreBundle/Command/InstallCommand.php @@ -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('Installing Wallabag.'); + $this->defaultInput = $input; + $this->defaultOutput = $output; + + $output->writeln('Installing Wallabag...'); $output->writeln(''); $this - ->checkStep($output) - ->setupStep($input, $output) + ->checkRequirements() + ->setupDatabase() + ->setupAdmin() + ->setupAsset() ; $output->writeln('Wallabag has been successfully installed.'); $output->writeln('Just execute `php app/console server:run` for using wallabag: http://localhost:8000'); } - protected function checkStep(OutputInterface $output) + protected function checkRequirements() { - $output->writeln('Checking system requirements.'); + $this->defaultOutput->writeln('Step 1 of 4. Checking system requirements.'); $fulfilled = true; // @TODO: find a better way to check requirements - $output->writeln('Check PCRE'); + $label = 'PCRE'; if (extension_loaded('pcre')) { - $output->writeln(' OK'); + $status = 'OK!'; + $help = ''; } else { $fulfilled = false; - $output->writeln(' ERROR'); - $output->writeln('You should enabled PCRE extension'); + $status = 'ERROR!'; + $help = 'You should enabled PCRE extension'; } + $rows[] = array($label, $status, $help); - $output->writeln('Check DOM'); + $label = 'DOM'; if (extension_loaded('DOM')) { - $output->writeln(' OK'); + $status = 'OK!'; + $help = ''; } else { $fulfilled = false; - $output->writeln(' ERROR'); - $output->writeln('You should enabled DOM extension'); + $status = '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.'); - } - - $output->writeln(''); - - return $this; - } - - protected function setupStep(InputInterface $input, OutputInterface $output) - { - $output->writeln('Setting up database.'); - - $this->setupDatabase($input, $output); - - // if ($this->getHelperSet()->get('dialog')->askConfirmation($output, 'Load fixtures (Y/N)?', false)) { - // $this->setupFixtures($input, $output); - // } - - $output->writeln(''); - $output->writeln('Administration setup.'); - - $this->setupAdmin($output); - - $output->writeln(''); - - return $this; - } - - protected function setupDatabase(InputInterface $input, OutputInterface $output) - { - if ($this->getHelperSet()->get('dialog')->askConfirmation($output, 'Drop current database (Y/N)?', true)) { - $connection = $this->getContainer()->get('doctrine')->getConnection(); - $params = $connection->getParams(); - - $name = isset($params['path']) ? $params['path'] : (isset($params['dbname']) ? $params['dbname'] : false); - unset($params['dbname']); - - if (!isset($params['path'])) { - $name = $connection->getDatabasePlatform()->quoteSingleIdentifier($name); - } - - $connection->getSchemaManager()->dropDatabase($name); + throw new \RuntimeException('Some system requirements are not fulfilled. Please check output messages and fix them.'); } 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('Success! Your system can run Wallabag properly.'); } - $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(''); + + return $this; } - protected function setupFixtures(InputInterface $input, OutputInterface $output) + protected function setupDatabase() { - $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('Step 2 of 4. Setting up database.'); + + // 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'); + + $this + ->runCommand('doctrine:database:drop', array('--force' => true)) + ->runCommand('doctrine:database:create') + ->runCommand('doctrine:schema:create') + ; + + return $this; + } + + if (!$this->isDatabasePresent()) { + $this->defaultOutput->writeln('Creating database and schema, clearing the cache'); + + $this + ->runCommand('doctrine:database:create') + ->runCommand('doctrine:schema:create') + ->runCommand('cache:clear') + ; + + return $this; + } + + $dialog = $this->getHelper('dialog'); + + if ($dialog->askConfirmation($this->defaultOutput, 'It appears that your database already exists. Would you like to reset it? (y/N) ', false)) { + $this->defaultOutput->writeln('Droping database, creating database and schema'); + + $this + ->runCommand('doctrine:database:drop', array('--force' => true)) + ->runCommand('doctrine:database:create') + ->runCommand('doctrine:schema:create') + ; + } elseif ($this->isSchemaPresent()) { + if ($dialog->askConfirmation($this->defaultOutput, 'Seems like your database contains schema. Do you want to reset it? (y/N) ', false)) { + $this->defaultOutput->writeln('Droping schema and creating schema'); + + $this + ->runCommand('doctrine:schema:drop', array('--force' => true)) + ->runCommand('doctrine:schema:create') + ; + } + } else { + $this->defaultOutput->writeln('Creating schema'); + + $this + ->runCommand('doctrine:schema:create') + ; + } + + $this->defaultOutput->writeln('Clearing the cache'); + $this->runCommand('cache:clear'); + + /* + if ($this->getHelperSet()->get('dialog')->askConfirmation($this->defaultOutput, 'Load fixtures (Y/N)?', 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); + } + */ + + $this->defaultOutput->writeln(''); + + return $this; } - protected function setupAdmin(OutputInterface $output) + protected function setupAdmin() { + $this->defaultOutput->writeln('Step 3 of 4. Administration setup.'); + $dialog = $this->getHelperSet()->get('dialog'); + + if (false === $dialog->askConfirmation($this->defaultOutput, 'Would you like to create a new user ? (y/N)', true)) { + return $this; + } + $em = $this->getContainer()->get('doctrine.orm.entity_manager'); $user = new User(); - $user->setUsername($dialog->ask($output, 'Username (default: wallabag) :', 'wallabag')); - $user->setPassword($dialog->ask($output, 'Password (default: wallabag) :', 'wallabag')); - $user->setEmail($dialog->ask($output, 'Email:', '')); + $user->setUsername($dialog->ask($this->defaultOutput, 'Username (default: wallabag) :', 'wallabag')); + $user->setPassword($dialog->ask($this->defaultOutput, 'Password (default: wallabag) :', 'wallabag')); + $user->setEmail($dialog->ask($this->defaultOutput, 'Email:', '')); $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); - - // $languageConfig = new LanguageConfig(); - // $languageConfig->setUserId($user->getId()); - // $languageConfig->setName('language'); - // $languageConfig->setValue('en_EN.UTF8'); - - // $em->persist($languageConfig); + $em->persist($config); $em->flush(); - } - protected function runCommand($command, InputInterface $input, OutputInterface $output) - { - $this - ->getApplication() - ->find($command) - ->run($input, $output) - ; + $this->defaultOutput->writeln(''); return $this; } + + protected function setupAsset() + { + $this->defaultOutput->writeln('Step 4 of 4. Installing assets.'); + + $this + ->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("$errorMessage"); + $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 index 000000000..68e034fa7 --- /dev/null +++ b/src/Wallabag/CoreBundle/Controller/ConfigController.php @@ -0,0 +1,128 @@ +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; + } +} diff --git a/src/Wallabag/CoreBundle/Controller/EntryController.php b/src/Wallabag/CoreBundle/Controller/EntryController.php index 89677befb..81ab77887 100644 --- a/src/Wallabag/CoreBundle/Controller/EntryController.php +++ b/src/Wallabag/CoreBundle/Controller/EntryController.php @@ -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 index 000000000..900e151d8 --- /dev/null +++ b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadConfigData.php @@ -0,0 +1,45 @@ +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; + } +} diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadEntryData.php b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadEntryData.php index 520b44b80..3be323ed7 100644 --- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadEntryData.php +++ b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadEntryData.php @@ -49,6 +49,6 @@ class LoadEntryData extends AbstractFixture implements OrderedFixtureInterface */ public function getOrder() { - return 20; + return 30; } } diff --git a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php index e4751f202..d99412f48 100644 --- a/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php +++ b/src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php @@ -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); diff --git a/src/Wallabag/CoreBundle/Entity/Config.php b/src/Wallabag/CoreBundle/Entity/Config.php index 045ca308e..7b4464a17 100644 --- a/src/Wallabag/CoreBundle/Entity/Config.php +++ b/src/Wallabag/CoreBundle/Entity/Config.php @@ -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->value; + 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->user; } } diff --git a/src/Wallabag/CoreBundle/Entity/User.php b/src/Wallabag/CoreBundle/Entity/User.php index c83250c37..193dfebc2 100644 --- a/src/Wallabag/CoreBundle/Entity/User.php +++ b/src/Wallabag/CoreBundle/Entity/User.php @@ -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 index 0742edbcb..000000000 --- a/src/Wallabag/CoreBundle/Entity/UsersConfig.php +++ /dev/null @@ -1,123 +0,0 @@ -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 index 000000000..e141789f1 --- /dev/null +++ b/src/Wallabag/CoreBundle/Form/Type/ChangePasswordType.php @@ -0,0 +1,39 @@ +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 index 000000000..a1e0ce47d --- /dev/null +++ b/src/Wallabag/CoreBundle/Form/Type/ConfigType.php @@ -0,0 +1,41 @@ +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 index 000000000..cfd644735 --- /dev/null +++ b/src/Wallabag/CoreBundle/Form/Type/EntryType.php @@ -0,0 +1,29 @@ +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 index 000000000..313a9aae8 --- /dev/null +++ b/src/Wallabag/CoreBundle/Form/Type/NewUserType.php @@ -0,0 +1,40 @@ +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 index 000000000..b479a0b58 --- /dev/null +++ b/src/Wallabag/CoreBundle/Form/Type/UserType.php @@ -0,0 +1,31 @@ +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 index 000000000..b2b1f627a --- /dev/null +++ b/src/Wallabag/CoreBundle/Repository/ConfigRepository.php @@ -0,0 +1,9 @@ +{% trans %}Wallabag configuration{% endtrans %} + +
+ {{ form_errors(configForm) }} + +
+
+ {{ form_label(configForm.theme) }} + {{ form_errors(configForm.theme) }} + {{ form_widget(configForm.theme) }} +
+
+ +
+
+ {{ form_label(configForm.items_per_page) }} + {{ form_errors(configForm.items_per_page) }} + {{ form_widget(configForm.items_per_page) }} +
+
+ +
+
+ {{ form_label(configForm.language) }} + {{ form_errors(configForm.language) }} + {{ form_widget(configForm.language) }} +
+
+ + {{ form_rest(configForm) }} +
+ +

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

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

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

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

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

+ +
+ {{ form_errors(newUserForm) }} + +
+
+ {{ form_label(newUserForm.username) }} + {{ form_errors(newUserForm.username) }} + {{ form_widget(newUserForm.username) }} +
+
+ +
+
+ {{ form_label(newUserForm.password) }} + {{ form_errors(newUserForm.password) }} + {{ form_widget(newUserForm.password) }} +
+
+ +
+
+ {{ form_label(newUserForm.email) }} + {{ form_errors(newUserForm.email) }} + {{ form_widget(newUserForm.email) }} +
+
+ + {{ form_rest(newUserForm) }} +
+{% endblock %} diff --git a/src/Wallabag/CoreBundle/Resources/views/_footer.html.twig b/src/Wallabag/CoreBundle/Resources/views/_footer.html.twig index 26411da9e..1b5f9a0fd 100644 --- a/src/Wallabag/CoreBundle/Resources/views/_footer.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/_footer.html.twig @@ -1,3 +1,3 @@ - + diff --git a/src/Wallabag/CoreBundle/Resources/views/_head.html.twig b/src/Wallabag/CoreBundle/Resources/views/_head.html.twig index 726b4163a..3bdbe8124 100755 --- a/src/Wallabag/CoreBundle/Resources/views/_head.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/_head.html.twig @@ -1,40 +1,40 @@ - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - - - - - + + + + + - - - - - - - - + + + + + + + + diff --git a/src/Wallabag/CoreBundle/Resources/views/_menu.html.twig b/src/Wallabag/CoreBundle/Resources/views/_menu.html.twig index 2e3b6d082..9a3cf053e 100644 --- a/src/Wallabag/CoreBundle/Resources/views/_menu.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/_menu.html.twig @@ -1,14 +1,14 @@ - - + + diff --git a/src/Wallabag/CoreBundle/Resources/views/_search_form.html.twig b/src/Wallabag/CoreBundle/Resources/views/_search_form.html.twig index 7eb1b67d8..1e6f327d2 100644 --- a/src/Wallabag/CoreBundle/Resources/views/_search_form.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/_search_form.html.twig @@ -1,9 +1,9 @@ diff --git a/src/Wallabag/CoreBundle/Resources/views/_top.html.twig b/src/Wallabag/CoreBundle/Resources/views/_top.html.twig index 34d925df5..9313071dc 100755 --- a/src/Wallabag/CoreBundle/Resources/views/_top.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/_top.html.twig @@ -1,5 +1,5 @@ -
-

- {% block logo %}wallabag logo{% endblock %} -

-
+
+

+ {% block logo %}wallabag logo{% endblock %} +

+
diff --git a/src/Wallabag/CoreBundle/Security/Authentication/Encoder/WallabagPasswordEncoder.php b/src/Wallabag/CoreBundle/Security/Authentication/Encoder/WallabagPasswordEncoder.php index 56f1affe3..fcfe418bf 100644 --- a/src/Wallabag/CoreBundle/Security/Authentication/Encoder/WallabagPasswordEncoder.php +++ b/src/Wallabag/CoreBundle/Security/Authentication/Encoder/WallabagPasswordEncoder.php @@ -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 index 000000000..5586f9762 --- /dev/null +++ b/src/Wallabag/CoreBundle/Security/Validator/WallabagUserPasswordValidator.php @@ -0,0 +1,48 @@ +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 index 000000000..64f6c3290 --- /dev/null +++ b/src/Wallabag/CoreBundle/Tests/Command/InstallCommandTest.php @@ -0,0 +1,274 @@ +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 index 000000000..9b1a0986e --- /dev/null +++ b/src/Wallabag/CoreBundle/Tests/Controller/ConfigControllerTest.php @@ -0,0 +1,350 @@ +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]); + } +} diff --git a/src/Wallabag/CoreBundle/Tests/Controller/EntryControllerTest.php b/src/Wallabag/CoreBundle/Tests/Controller/EntryControllerTest.php index 7276f8e4e..2634141e5 100644 --- a/src/Wallabag/CoreBundle/Tests/Controller/EntryControllerTest.php +++ b/src/Wallabag/CoreBundle/Tests/Controller/EntryControllerTest.php @@ -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); diff --git a/src/Wallabag/CoreBundle/Tests/Controller/WallabagRestControllerTest.php b/src/Wallabag/CoreBundle/Tests/Controller/WallabagRestControllerTest.php index d77e23037..fcfa8ccf9 100644 --- a/src/Wallabag/CoreBundle/Tests/Controller/WallabagRestControllerTest.php +++ b/src/Wallabag/CoreBundle/Tests/Controller/WallabagRestControllerTest.php @@ -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') diff --git a/src/Wallabag/CoreBundle/Tests/WallabagTestCase.php b/src/Wallabag/CoreBundle/Tests/WallabagTestCase.php index a80b8bac4..22016d8ed 100644 --- a/src/Wallabag/CoreBundle/Tests/WallabagTestCase.php +++ b/src/Wallabag/CoreBundle/Tests/WallabagTestCase.php @@ -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);