mirror of
https://github.com/wallabag/wallabag.git
synced 2024-11-15 13:31:13 +00:00
Merge pull request #1062 from wallabag/v2-relation-entry-user
add a real relation between user and entry
This commit is contained in:
commit
89c03230c3
17 changed files with 620 additions and 112 deletions
|
@ -28,6 +28,7 @@ class AppKernel extends Kernel
|
|||
$bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
|
||||
$bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle();
|
||||
$bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle();
|
||||
$bundles[] = new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle();
|
||||
}
|
||||
|
||||
return $bundles;
|
||||
|
|
|
@ -34,5 +34,12 @@
|
|||
<arg value="cache:clear"/>
|
||||
<arg value="--env=test"/>
|
||||
</exec>
|
||||
<exec executable="php">
|
||||
<arg value="${basedir}/../app/console"/>
|
||||
<arg value="doctrine:fixtures:load"/>
|
||||
<arg value="--no-interaction"/>
|
||||
<arg value="--purge-with-truncate"/>
|
||||
<arg value="--env=test"/>
|
||||
</exec>
|
||||
</target>
|
||||
</project>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
security:
|
||||
encoders:
|
||||
Wallabag\CoreBundle\Entity\Users:
|
||||
Wallabag\CoreBundle\Entity\User:
|
||||
algorithm: sha1
|
||||
encode_as_base64: false
|
||||
iterations: 1
|
||||
|
@ -11,7 +11,7 @@ security:
|
|||
|
||||
providers:
|
||||
administrators:
|
||||
entity: { class: WallabagCoreBundle:Users, property: username }
|
||||
entity: { class: WallabagCoreBundle:User, property: username }
|
||||
|
||||
# the main part of the security, where you can set up firewalls
|
||||
# for specific sections of your app
|
||||
|
@ -23,35 +23,35 @@ security:
|
|||
pattern: ^/login$
|
||||
anonymous: ~
|
||||
|
||||
# secured_area:
|
||||
# pattern: ^/
|
||||
# anonymous: ~
|
||||
# form_login:
|
||||
# login_path: /login
|
||||
#
|
||||
# use_forward: false
|
||||
#
|
||||
# check_path: /login_check
|
||||
#
|
||||
# post_only: true
|
||||
#
|
||||
# always_use_default_target_path: true
|
||||
# default_target_path: /
|
||||
# target_path_parameter: redirect_url
|
||||
# use_referer: true
|
||||
#
|
||||
# failure_path: null
|
||||
# failure_forward: false
|
||||
#
|
||||
# username_parameter: _username
|
||||
# password_parameter: _password
|
||||
#
|
||||
# csrf_parameter: _csrf_token
|
||||
# intention: authenticate
|
||||
#
|
||||
# logout:
|
||||
# path: /logout
|
||||
# target: /
|
||||
secured_area:
|
||||
pattern: ^/
|
||||
anonymous: ~
|
||||
form_login:
|
||||
login_path: /login
|
||||
|
||||
use_forward: false
|
||||
|
||||
check_path: /login_check
|
||||
|
||||
post_only: true
|
||||
|
||||
always_use_default_target_path: true
|
||||
default_target_path: /
|
||||
target_path_parameter: redirect_url
|
||||
use_referer: true
|
||||
|
||||
failure_path: null
|
||||
failure_forward: false
|
||||
|
||||
username_parameter: _username
|
||||
password_parameter: _password
|
||||
|
||||
csrf_parameter: _csrf_token
|
||||
intention: authenticate
|
||||
|
||||
logout:
|
||||
path: /logout
|
||||
target: /
|
||||
|
||||
access_control:
|
||||
- { path: ^/api/doc, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
# Learn more about services, parameters and containers at
|
||||
# http://symfony.com/doc/current/book/service_container.html
|
||||
parameters:
|
||||
# parameter_name: value
|
||||
security.authentication.provider.dao.class: Wallabag\CoreBundle\Security\Authentication\Provider\WallabagAuthenticationProvider
|
||||
security.encoder.digest.class: Wallabag\CoreBundle\Security\Authentication\Encoder\WallabagPasswordEncoder
|
||||
|
||||
services:
|
||||
# service_name:
|
||||
|
|
|
@ -83,6 +83,7 @@
|
|||
"wallabag/Fivefilters_Libraries": "dev-master"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/doctrine-fixtures-bundle": "dev-master",
|
||||
"sensio/generator-bundle": "~2.5",
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
|
|
140
composer.lock
generated
140
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "5005a650aa4368bd3485939efd9e24ac",
|
||||
"hash": "16c2143e6e1977d625f5557f07dfc118",
|
||||
"packages": [
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
|
@ -1666,21 +1666,20 @@
|
|||
},
|
||||
{
|
||||
"name": "robmorgan/phinx",
|
||||
"version": "v0.4.1",
|
||||
"version": "v0.4.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/robmorgan/phinx.git",
|
||||
"reference": "357210707c000f50edea802d84b74724ad122478"
|
||||
"reference": "1bc1396392d4073b8b29ee5289e445889cbc12b5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/robmorgan/phinx/zipball/357210707c000f50edea802d84b74724ad122478",
|
||||
"reference": "357210707c000f50edea802d84b74724ad122478",
|
||||
"url": "https://api.github.com/repos/robmorgan/phinx/zipball/1bc1396392d4073b8b29ee5289e445889cbc12b5",
|
||||
"reference": "1bc1396392d4073b8b29ee5289e445889cbc12b5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.2",
|
||||
"symfony/class-loader": "~2.6.0",
|
||||
"symfony/config": "~2.6.0",
|
||||
"symfony/console": "~2.6.0",
|
||||
"symfony/yaml": "~2.6.0"
|
||||
|
@ -1694,8 +1693,8 @@
|
|||
],
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Phinx": "src/"
|
||||
"psr-4": {
|
||||
"Phinx\\": "src/Phinx"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
|
@ -1708,6 +1707,12 @@
|
|||
"email": "robbym@gmail.com",
|
||||
"homepage": "http://robmorgan.id.au",
|
||||
"role": "Lead Developer"
|
||||
},
|
||||
{
|
||||
"name": "Woody Gilk",
|
||||
"email": "woody.gilk@gmail.com",
|
||||
"homepage": "http://shadowhand.me",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Phinx makes it ridiculously easy to manage the database migrations for your PHP app.",
|
||||
|
@ -1719,7 +1724,7 @@
|
|||
"migrations",
|
||||
"phinx"
|
||||
],
|
||||
"time": "2014-12-23 06:06:14"
|
||||
"time": "2015-02-08 03:41:44"
|
||||
},
|
||||
{
|
||||
"name": "sensio/distribution-bundle",
|
||||
|
@ -2871,6 +2876,120 @@
|
|||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "doctrine/data-fixtures",
|
||||
"version": "v1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/data-fixtures.git",
|
||||
"reference": "b4a135c7db56ecc4602b54a2184368f440cac33e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/b4a135c7db56ecc4602b54a2184368f440cac33e",
|
||||
"reference": "b4a135c7db56ecc4602b54a2184368f440cac33e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/common": ">=2.2,<2.5-dev",
|
||||
"php": ">=5.3.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/orm": ">=2.2,<2.5-dev"
|
||||
},
|
||||
"suggest": {
|
||||
"doctrine/mongodb-odm": "For loading MongoDB ODM fixtures",
|
||||
"doctrine/orm": "For loading ORM fixtures",
|
||||
"doctrine/phpcr-odm": "For loading PHPCR ODM fixtures"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Doctrine\\Common\\DataFixtures": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com",
|
||||
"homepage": "http://www.jwage.com/",
|
||||
"role": "Creator"
|
||||
}
|
||||
],
|
||||
"description": "Data Fixtures for all Doctrine Object Managers",
|
||||
"homepage": "http://www.doctrine-project.org",
|
||||
"keywords": [
|
||||
"database"
|
||||
],
|
||||
"time": "2013-07-10 17:04:07"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/doctrine-fixtures-bundle",
|
||||
"version": "dev-master",
|
||||
"target-dir": "Doctrine/Bundle/FixturesBundle",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/DoctrineFixturesBundle.git",
|
||||
"reference": "c5ff0542772102ddd4e2fbe173e9ad40ad67c22f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/DoctrineFixturesBundle/zipball/c5ff0542772102ddd4e2fbe173e9ad40ad67c22f",
|
||||
"reference": "c5ff0542772102ddd4e2fbe173e9ad40ad67c22f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/data-fixtures": "~1.0",
|
||||
"doctrine/doctrine-bundle": "~1.0",
|
||||
"php": ">=5.3.2",
|
||||
"symfony/doctrine-bridge": "~2.1"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Doctrine\\Bundle\\FixturesBundle": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
},
|
||||
{
|
||||
"name": "Doctrine Project",
|
||||
"homepage": "http://www.doctrine-project.org"
|
||||
},
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
}
|
||||
],
|
||||
"description": "Symfony DoctrineFixturesBundle",
|
||||
"homepage": "http://www.doctrine-project.org",
|
||||
"keywords": [
|
||||
"Fixture",
|
||||
"persistence"
|
||||
],
|
||||
"time": "2015-01-19 02:21:37"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
"version": "1.0.4",
|
||||
|
@ -3834,7 +3953,8 @@
|
|||
"wallabag/phpepub": 20,
|
||||
"wallabag/php-readability": 20,
|
||||
"wallabag/phpmobi": 20,
|
||||
"wallabag/fivefilters_libraries": 20
|
||||
"wallabag/fivefilters_libraries": 20,
|
||||
"doctrine/doctrine-fixtures-bundle": 20
|
||||
},
|
||||
"prefer-stable": true,
|
||||
"prefer-lowest": false,
|
||||
|
|
|
@ -19,8 +19,7 @@ class EntryController extends Controller
|
|||
*/
|
||||
public function addEntryAction(Request $request)
|
||||
{
|
||||
$entry = new Entry();
|
||||
$entry->setUserId(1);
|
||||
$entry = new Entry($this->getUser());
|
||||
|
||||
$form = $this->createFormBuilder($entry)
|
||||
->add('url', 'url')
|
||||
|
@ -60,10 +59,10 @@ class EntryController extends Controller
|
|||
*/
|
||||
public function showUnreadAction()
|
||||
{
|
||||
$repository = $this->getDoctrine()->getRepository('WallabagCoreBundle:Entry');
|
||||
// TODO don't give the user ID like this
|
||||
// TODO change pagination
|
||||
$entries = $repository->findUnreadByUser(1, 0);
|
||||
$entries = $this->getDoctrine()
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findUnreadByUser($this->getUser()->getId(), 0);
|
||||
|
||||
return $this->render(
|
||||
'WallabagCoreBundle:Entry:entries.html.twig',
|
||||
|
@ -79,10 +78,10 @@ class EntryController extends Controller
|
|||
*/
|
||||
public function showArchiveAction()
|
||||
{
|
||||
$repository = $this->getDoctrine()->getRepository('WallabagCoreBundle:Entry');
|
||||
// TODO don't give the user ID like this
|
||||
// TODO change pagination
|
||||
$entries = $repository->findArchiveByUser(1, 0);
|
||||
$entries = $this->getDoctrine()
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findArchiveByUser($this->getUser()->getId(), 0);
|
||||
|
||||
return $this->render(
|
||||
'WallabagCoreBundle:Entry:entries.html.twig',
|
||||
|
@ -98,10 +97,10 @@ class EntryController extends Controller
|
|||
*/
|
||||
public function showStarredAction()
|
||||
{
|
||||
$repository = $this->getDoctrine()->getRepository('WallabagCoreBundle:Entry');
|
||||
// TODO don't give the user ID like this
|
||||
// TODO change pagination
|
||||
$entries = $repository->findStarredByUser(1, 0);
|
||||
$entries = $this->getDoctrine()
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findStarredByUser($this->getUser()->getId(), 0);
|
||||
|
||||
return $this->render(
|
||||
'WallabagCoreBundle:Entry:entries.html.twig',
|
||||
|
|
35
src/Wallabag/CoreBundle/DataFixtures/ORM/LoadEntryData.php
Normal file
35
src/Wallabag/CoreBundle/DataFixtures/ORM/LoadEntryData.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?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\Entry;
|
||||
|
||||
class LoadEntryData extends AbstractFixture implements OrderedFixtureInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function load(ObjectManager $manager)
|
||||
{
|
||||
$entry1 = new Entry($this->getReference('admin-user'));
|
||||
$entry1->setUrl('http://0.0.0.0');
|
||||
$entry1->setTitle('test title');
|
||||
$entry1->setContent('This is my content /o/');
|
||||
|
||||
$manager->persist($entry1);
|
||||
$manager->flush();
|
||||
|
||||
$this->addReference('entry1', $entry1);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getOrder()
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
}
|
34
src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php
Normal file
34
src/Wallabag/CoreBundle/DataFixtures/ORM/LoadUserData.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?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\User;
|
||||
|
||||
class LoadUserData extends AbstractFixture implements OrderedFixtureInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function load(ObjectManager $manager)
|
||||
{
|
||||
$userAdmin = new User();
|
||||
$userAdmin->setUsername('admin');
|
||||
$userAdmin->setPassword('test');
|
||||
|
||||
$manager->persist($userAdmin);
|
||||
$manager->flush();
|
||||
|
||||
$this->addReference('admin-user', $userAdmin);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getOrder()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
}
|
|
@ -81,13 +81,6 @@ class Entry
|
|||
*/
|
||||
private $updatedAt;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* @ORM\Column(name="user_id", type="decimal", precision=10, scale=0, nullable=true)
|
||||
*/
|
||||
private $userId;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
|
@ -123,6 +116,19 @@ class Entry
|
|||
*/
|
||||
private $isPublic;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="User", inversedBy="entries")
|
||||
*/
|
||||
private $user;
|
||||
|
||||
/*
|
||||
* @param User $user
|
||||
*/
|
||||
public function __construct(User $user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get id
|
||||
*
|
||||
|
@ -263,26 +269,11 @@ class Entry
|
|||
}
|
||||
|
||||
/**
|
||||
* Set userId
|
||||
*
|
||||
* @param string $userId
|
||||
* @return Entry
|
||||
* @return User
|
||||
*/
|
||||
public function setUserId($userId)
|
||||
public function getUser()
|
||||
{
|
||||
$this->userId = $userId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get userId
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUserId()
|
||||
{
|
||||
return $this->userId;
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Wallabag\CoreBundle\Entity;
|
||||
|
||||
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;
|
||||
|
@ -78,10 +79,16 @@ class User implements AdvancedUserInterface, \Serializable
|
|||
*/
|
||||
private $updatedAt;
|
||||
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity="Entry", mappedBy="user", cascade={"remove"})
|
||||
*/
|
||||
private $entries;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->isActive = true;
|
||||
$this->salt = md5(uniqid(null, true));
|
||||
$this->salt = md5(uniqid(null, true));
|
||||
$this->entries = new ArrayCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -154,7 +161,11 @@ class User implements AdvancedUserInterface, \Serializable
|
|||
*/
|
||||
public function setPassword($password)
|
||||
{
|
||||
$this->password = $password;
|
||||
if (!$password && 0 === strlen($password)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->password = sha1($password.$this->getUsername().$this->getSalt());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@ -231,6 +242,26 @@ class User implements AdvancedUserInterface, \Serializable
|
|||
return $this->updatedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Entry $entry
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
public function addEntry(Entry $entry)
|
||||
{
|
||||
$this->entries[] = $entry;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArrayCollection<Entry>
|
||||
*/
|
||||
public function getEntries()
|
||||
{
|
||||
return $this->entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
|
|
@ -11,19 +11,20 @@ class EntryRepository extends EntityRepository
|
|||
/**
|
||||
* Retrieves unread entries for a user
|
||||
*
|
||||
* @param $userId
|
||||
* @param $firstResult
|
||||
* @param int $maxResults
|
||||
* @param int $userId
|
||||
* @param int $firstResult
|
||||
* @param int $maxResults
|
||||
*
|
||||
* @return Paginator
|
||||
*/
|
||||
public function findUnreadByUser($userId, $firstResult, $maxResults = 12)
|
||||
{
|
||||
$qb = $this->createQueryBuilder('e')
|
||||
->select('e')
|
||||
->setFirstResult($firstResult)
|
||||
->setMaxResults($maxResults)
|
||||
->leftJoin('e.user', 'u')
|
||||
->where('e.isArchived = false')
|
||||
->andWhere('e.userId =:userId')->setParameter('userId', $userId)
|
||||
->andWhere('u.id =:userId')->setParameter('userId', $userId)
|
||||
->andWhere('e.isDeleted=false')
|
||||
->orderBy('e.createdAt', 'desc')
|
||||
->getQuery();
|
||||
|
@ -36,9 +37,10 @@ class EntryRepository extends EntityRepository
|
|||
/**
|
||||
* Retrieves read entries for a user
|
||||
*
|
||||
* @param $userId
|
||||
* @param $firstResult
|
||||
* @param int $maxResults
|
||||
* @param int $userId
|
||||
* @param int $firstResult
|
||||
* @param int $maxResults
|
||||
*
|
||||
* @return Paginator
|
||||
*/
|
||||
public function findArchiveByUser($userId, $firstResult, $maxResults = 12)
|
||||
|
@ -47,8 +49,9 @@ class EntryRepository extends EntityRepository
|
|||
->select('e')
|
||||
->setFirstResult($firstResult)
|
||||
->setMaxResults($maxResults)
|
||||
->leftJoin('e.user', 'u')
|
||||
->where('e.isArchived = true')
|
||||
->andWhere('e.userId =:userId')->setParameter('userId', $userId)
|
||||
->andWhere('u.id =:userId')->setParameter('userId', $userId)
|
||||
->andWhere('e.isDeleted=false')
|
||||
->orderBy('e.createdAt', 'desc')
|
||||
->getQuery();
|
||||
|
@ -61,9 +64,10 @@ class EntryRepository extends EntityRepository
|
|||
/**
|
||||
* Retrieves starred entries for a user
|
||||
*
|
||||
* @param $userId
|
||||
* @param $firstResult
|
||||
* @param int $maxResults
|
||||
* @param int $userId
|
||||
* @param int $firstResult
|
||||
* @param int $maxResults
|
||||
*
|
||||
* @return Paginator
|
||||
*/
|
||||
public function findStarredByUser($userId, $firstResult, $maxResults = 12)
|
||||
|
@ -72,9 +76,10 @@ class EntryRepository extends EntityRepository
|
|||
->select('e')
|
||||
->setFirstResult($firstResult)
|
||||
->setMaxResults($maxResults)
|
||||
->leftJoin('e.user', 'u')
|
||||
->where('e.isStarred = true')
|
||||
->andWhere('e.userId =:userId')->setParameter('userId', $userId)
|
||||
->andWhere('e.isDeleted=false')
|
||||
->andWhere('u.id =:userId')->setParameter('userId', $userId)
|
||||
->andWhere('e.isDeleted = false')
|
||||
->orderBy('e.createdAt', 'desc')
|
||||
->getQuery();
|
||||
|
||||
|
@ -83,22 +88,34 @@ class EntryRepository extends EntityRepository
|
|||
return $paginator;
|
||||
}
|
||||
|
||||
public function findEntries($userId, $isArchived, $isStarred, $isDeleted, $sort, $order)
|
||||
/**
|
||||
* Find Entries
|
||||
*
|
||||
* @param int $userId
|
||||
* @param bool $isArchived
|
||||
* @param bool $isStarred
|
||||
* @param bool $isDeleted
|
||||
* @param string $sort
|
||||
* @param string $order
|
||||
*
|
||||
* @return ArrayCollection
|
||||
*/
|
||||
public function findEntries($userId, $isArchived = null, $isStarred = null, $isDeleted = null, $sort = 'created', $order = 'ASC')
|
||||
{
|
||||
$qb = $this->createQueryBuilder('e')
|
||||
->select('e')
|
||||
->where('e.userId =:userId')->setParameter('userId', $userId);
|
||||
->leftJoin('e.user', 'u')
|
||||
->where('u.id =:userId')->setParameter('userId', $userId);
|
||||
|
||||
if (!is_null($isArchived)) {
|
||||
$qb->andWhere('e.isArchived =:isArchived')->setParameter('isArchived', $isArchived);
|
||||
if (null !== $isArchived) {
|
||||
$qb->andWhere('e.isArchived =:isArchived')->setParameter('isArchived', (bool) $isArchived);
|
||||
}
|
||||
|
||||
if (!is_null($isStarred)) {
|
||||
$qb->andWhere('e.isStarred =:isStarred')->setParameter('isStarred', $isStarred);
|
||||
if (null !== $isStarred) {
|
||||
$qb->andWhere('e.isStarred =:isStarred')->setParameter('isStarred', (bool) $isStarred);
|
||||
}
|
||||
|
||||
if (!is_null($isDeleted)) {
|
||||
$qb->andWhere('e.isDeleted =:isDeleted')->setParameter('isDeleted', $isDeleted);
|
||||
if (null !== $isDeleted) {
|
||||
$qb->andWhere('e.isDeleted =:isDeleted')->setParameter('isDeleted', (bool) $isDeleted);
|
||||
}
|
||||
|
||||
if ('created' === $sort) {
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Security\Authentication\Encoder;
|
||||
|
||||
use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder;
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
|
||||
/**
|
||||
* This override just add en extra variable (username) to be able to salt the password
|
||||
* the way Wallabag v1 does. It will avoid to break compatibility with Wallabag v1
|
||||
*
|
||||
*/
|
||||
class WallabagPasswordEncoder extends BasePasswordEncoder
|
||||
{
|
||||
private $algorithm;
|
||||
private $encodeHashAsBase64;
|
||||
private $iterations;
|
||||
private $username = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $algorithm The digest algorithm to use
|
||||
* @param bool $encodeHashAsBase64 Whether to base64 encode the password hash
|
||||
* @param int $iterations The number of iterations to use to stretch the password hash
|
||||
*/
|
||||
public function __construct($algorithm = 'sha512', $encodeHashAsBase64 = true, $iterations = 5000)
|
||||
{
|
||||
$this->algorithm = $algorithm;
|
||||
$this->encodeHashAsBase64 = $encodeHashAsBase64;
|
||||
$this->iterations = $iterations;
|
||||
}
|
||||
|
||||
public function setUsername($username)
|
||||
{
|
||||
$this->username = $username;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
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.');
|
||||
}
|
||||
|
||||
if (!in_array($this->algorithm, hash_algos(), true)) {
|
||||
throw new \LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm));
|
||||
}
|
||||
|
||||
$salted = $this->mergePasswordAndSalt($raw, $salt);
|
||||
$digest = hash($this->algorithm, $salted, true);
|
||||
|
||||
// "stretch" hash
|
||||
for ($i = 1; $i < $this->iterations; $i++) {
|
||||
$digest = hash($this->algorithm, $digest.$salted, true);
|
||||
}
|
||||
|
||||
return $this->encodeHashAsBase64 ? base64_encode($digest) : bin2hex($digest);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* We inject the username inside the salted password
|
||||
*/
|
||||
protected function mergePasswordAndSalt($password, $salt)
|
||||
{
|
||||
if (empty($salt)) {
|
||||
return $password;
|
||||
}
|
||||
|
||||
return $password.$this->username.$salt;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isPasswordValid($encoded, $raw, $salt)
|
||||
{
|
||||
return !$this->isPasswordTooLong($raw) && $this->comparePasswords($encoded, $this->encodePassword($raw, $salt));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Security\Authentication\Provider;
|
||||
|
||||
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
|
||||
use Symfony\Component\Security\Core\User\UserProviderInterface;
|
||||
use Symfony\Component\Security\Core\User\UserCheckerInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
|
||||
use Symfony\Component\Security\Core\Exception\AuthenticationServiceException;
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
|
||||
use Symfony\Component\Security\Core\Authentication\Provider\UserAuthenticationProvider;
|
||||
|
||||
class WallabagAuthenticationProvider extends UserAuthenticationProvider
|
||||
{
|
||||
private $encoderFactory;
|
||||
private $userProvider;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param UserProviderInterface $userProvider An UserProviderInterface instance
|
||||
* @param UserCheckerInterface $userChecker An UserCheckerInterface instance
|
||||
* @param string $providerKey The provider key
|
||||
* @param EncoderFactoryInterface $encoderFactory An EncoderFactoryInterface instance
|
||||
* @param bool $hideUserNotFoundExceptions Whether to hide user not found exception or not
|
||||
*/
|
||||
public function __construct(UserProviderInterface $userProvider, UserCheckerInterface $userChecker, $providerKey, EncoderFactoryInterface $encoderFactory, $hideUserNotFoundExceptions = true)
|
||||
{
|
||||
parent::__construct($userChecker, $providerKey, $hideUserNotFoundExceptions);
|
||||
|
||||
$this->encoderFactory = $encoderFactory;
|
||||
$this->userProvider = $userProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function checkAuthentication(UserInterface $user, UsernamePasswordToken $token)
|
||||
{
|
||||
$currentUser = $token->getUser();
|
||||
if ($currentUser instanceof UserInterface) {
|
||||
if ($currentUser->getPassword() !== $user->getPassword()) {
|
||||
throw new BadCredentialsException('The credentials were changed from another session.');
|
||||
}
|
||||
} else {
|
||||
if ("" === ($presentedPassword = $token->getCredentials())) {
|
||||
throw new BadCredentialsException('The presented password cannot be empty.');
|
||||
}
|
||||
|
||||
// give username, it's used to hash the password
|
||||
$encoder = $this->encoderFactory->getEncoder($user);
|
||||
$encoder->setUsername($user->getUsername());
|
||||
|
||||
if (!$encoder->isPasswordValid($user->getPassword(), $presentedPassword, $user->getSalt())) {
|
||||
throw new BadCredentialsException('The presented password is invalid.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function retrieveUser($username, UsernamePasswordToken $token)
|
||||
{
|
||||
$user = $token->getUser();
|
||||
if ($user instanceof UserInterface) {
|
||||
return $user;
|
||||
}
|
||||
|
||||
try {
|
||||
$user = $this->userProvider->loadUserByUsername($username);
|
||||
|
||||
if (!$user instanceof UserInterface) {
|
||||
throw new AuthenticationServiceException('The user provider must return a UserInterface object.');
|
||||
}
|
||||
|
||||
return $user;
|
||||
} catch (UsernameNotFoundException $notFound) {
|
||||
$notFound->setUsername($username);
|
||||
throw $notFound;
|
||||
} catch (\Exception $repositoryProblem) {
|
||||
$ex = new AuthenticationServiceException($repositoryProblem->getMessage(), 0, $repositoryProblem);
|
||||
$ex->setToken($token);
|
||||
throw $ex;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,13 +2,24 @@
|
|||
|
||||
namespace Wallabag\CoreBundle\Tests\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Wallabag\CoreBundle\Tests\WallabagTestCase;
|
||||
|
||||
class EntryControllerTest extends WebTestCase
|
||||
class EntryControllerTest extends WallabagTestCase
|
||||
{
|
||||
public function testLogin()
|
||||
{
|
||||
$client = $this->getClient();
|
||||
|
||||
$crawler = $client->request('GET', '/new');
|
||||
|
||||
$this->assertEquals(302, $client->getResponse()->getStatusCode());
|
||||
$this->assertContains('login', $client->getResponse()->headers->get('location'));
|
||||
}
|
||||
|
||||
public function testGetNew()
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->logIn();
|
||||
$client = $this->getClient();
|
||||
|
||||
$crawler = $client->request('GET', '/new');
|
||||
|
||||
|
@ -20,7 +31,8 @@ class EntryControllerTest extends WebTestCase
|
|||
|
||||
public function testPostNewEmpty()
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->logIn();
|
||||
$client = $this->getClient();
|
||||
|
||||
$crawler = $client->request('GET', '/new');
|
||||
|
||||
|
@ -37,7 +49,8 @@ class EntryControllerTest extends WebTestCase
|
|||
|
||||
public function testPostNewOk()
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->logIn();
|
||||
$client = $this->getClient();
|
||||
|
||||
$crawler = $client->request('GET', '/new');
|
||||
|
||||
|
@ -55,13 +68,14 @@ class EntryControllerTest extends WebTestCase
|
|||
|
||||
$crawler = $client->followRedirect();
|
||||
|
||||
$this->assertCount(1, $alert = $crawler->filter('h2 a')->extract(array('_text')));
|
||||
$this->assertGreaterThan(1, $alert = $crawler->filter('h2 a')->extract(array('_text')));
|
||||
$this->assertContains('Mailjet', $alert[0]);
|
||||
}
|
||||
|
||||
public function testArchive()
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->logIn();
|
||||
$client = $this->getClient();
|
||||
|
||||
$crawler = $client->request('GET', '/archive');
|
||||
|
||||
|
@ -70,7 +84,8 @@ class EntryControllerTest extends WebTestCase
|
|||
|
||||
public function testStarred()
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->logIn();
|
||||
$client = $this->getClient();
|
||||
|
||||
$crawler = $client->request('GET', '/starred');
|
||||
|
||||
|
@ -79,13 +94,18 @@ class EntryControllerTest extends WebTestCase
|
|||
|
||||
public function testView()
|
||||
{
|
||||
$client = static::createClient();
|
||||
$this->logIn();
|
||||
$client = $this->getClient();
|
||||
|
||||
$content = $client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findOneByIsArchived(false);
|
||||
|
||||
if (!$content) {
|
||||
$this->markTestSkipped('No content found in db.');
|
||||
}
|
||||
|
||||
$crawler = $client->request('GET', '/view/'.$content->getId());
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Tests\Controller;
|
||||
|
||||
use Wallabag\CoreBundle\Tests\WallabagTestCase;
|
||||
|
||||
class SecurityControllerTest extends WallabagTestCase
|
||||
{
|
||||
public function testLogin()
|
||||
{
|
||||
$client = $this->getClient();
|
||||
|
||||
$crawler = $client->request('GET', '/new');
|
||||
|
||||
$this->assertEquals(302, $client->getResponse()->getStatusCode());
|
||||
$this->assertContains('login', $client->getResponse()->headers->get('location'));
|
||||
}
|
||||
|
||||
public function testLoginFail()
|
||||
{
|
||||
$client = $this->getClient();
|
||||
|
||||
$crawler = $client->request('GET', '/login');
|
||||
|
||||
$form = $crawler->filter('button[type=submit]')->form();
|
||||
$data = array(
|
||||
'_username' => 'admin',
|
||||
'_password' => 'admin',
|
||||
);
|
||||
|
||||
$client->submit($form, $data);
|
||||
|
||||
$this->assertEquals(302, $client->getResponse()->getStatusCode());
|
||||
$this->assertContains('login', $client->getResponse()->headers->get('location'));
|
||||
|
||||
$crawler = $client->followRedirect();
|
||||
|
||||
$this->assertContains('Bad credentials', $client->getResponse()->getContent());
|
||||
}
|
||||
}
|
34
src/Wallabag/CoreBundle/Tests/WallabagTestCase.php
Normal file
34
src/Wallabag/CoreBundle/Tests/WallabagTestCase.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Tests;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
use Symfony\Component\BrowserKit\Cookie;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
|
||||
|
||||
class WallabagTestCase extends WebTestCase
|
||||
{
|
||||
private $client = null;
|
||||
|
||||
public function getClient()
|
||||
{
|
||||
return $this->client;
|
||||
}
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->client = static::createClient();
|
||||
}
|
||||
|
||||
public function logIn()
|
||||
{
|
||||
$crawler = $this->client->request('GET', '/login');
|
||||
$form = $crawler->filter('button[type=submit]')->form();
|
||||
$data = array(
|
||||
'_username' => 'admin',
|
||||
'_password' => 'test',
|
||||
);
|
||||
|
||||
$this->client->submit($form, $data);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue