Merge pull request #1095 from wallabag/v2-config

V2 config
This commit is contained in:
Nicolas Lœuillet 2015-02-23 20:56:09 +01:00
commit 0e7971d835
33 changed files with 1602 additions and 349 deletions

View 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: ~
nelmio_api_doc: ~

View file

@ -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);
}

View 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
# default user config
items_on_page: 12
theme: baggy
language: en_US

View 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:

View 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.');
}
$output->writeln('');
return $this;
}
protected function setupStep(InputInterface $input, OutputInterface $output)
{
$output->writeln('<info>Setting up database.</info>');
$this->setupDatabase($input, $output);
// if ($this->getHelperSet()->get('dialog')->askConfirmation($output, '<question>Load fixtures (Y/N)?</question>', false)) {
// $this->setupFixtures($input, $output);
// }
$output->writeln('');
$output->writeln('<info>Administration setup.</info>');
$this->setupAdmin($output);
$output->writeln('');
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();
$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('<info>Success! Your system can run Wallabag properly.</info>');
}
$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('<info><comment>Step 2 of 4.</comment> Setting up database.</info>');
// 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, '<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');
$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');
$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, '<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);
}
*/
$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);
// $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('<info><comment>Step 4 of 4.</comment> Installing assets.</info>');
$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("<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'));
}
}

View file

@ -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;
}
}

View 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);

View file

@ -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;
}
}

View file

@ -49,6 +49,6 @@ class LoadEntryData extends AbstractFixture implements OrderedFixtureInterface
*/
public function getOrder()
{
return 20;
return 30;
}
}

View 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);

View 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->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;
}
}

View 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();
}
/**

View file

@ -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;
}
}

View file

@ -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';
}
}

View file

@ -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';
}
}

View file

@ -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';
}
}

View file

@ -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';
}
}

View file

@ -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';
}
}

View file

@ -0,0 +1,9 @@
<?php
namespace Wallabag\CoreBundle\Repository;
use Doctrine\ORM\EntityRepository;
class ConfigRepository extends EntityRepository
{
}

View file

@ -1,3 +1,7 @@
_wllbg:
entry:
resource: "@WallabagCoreBundle/Controller/EntryController.php"
type: annotation
config:
resource: "@WallabagCoreBundle/Controller/ConfigController.php"
type: annotation

View file

@ -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 %}

View 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>

View file

@ -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>

View 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>

View 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>

View file

@ -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>

View 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;
}

View file

@ -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);
}
}
}

View file

@ -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());
}
}

View file

@ -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]);
}
}

View 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);

View 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')

View 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);