mirror of
https://github.com/wallabag/wallabag.git
synced 2024-11-26 11:01:04 +00:00
Merge pull request #1545 from wallabag/v2-user-tag
v2 – Remove user reference in tag
This commit is contained in:
commit
dad1c546a5
13 changed files with 159 additions and 103 deletions
|
@ -27,7 +27,7 @@ class WallabagRestController extends FOSRestController
|
|||
->findOneByLabel($label);
|
||||
|
||||
if (is_null($tagEntity)) {
|
||||
$tagEntity = new Tag($this->getUser());
|
||||
$tagEntity = new Tag();
|
||||
$tagEntity->setLabel($label);
|
||||
}
|
||||
|
||||
|
@ -74,8 +74,7 @@ class WallabagRestController extends FOSRestController
|
|||
$perPage = (int) $request->query->get('perPage', 30);
|
||||
$tags = $request->query->get('tags', []);
|
||||
|
||||
$pager = $this
|
||||
->getDoctrine()
|
||||
$pager = $this->getDoctrine()
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findEntries($this->getUser()->getId(), $isArchived, $isStarred, $sort, $order);
|
||||
|
||||
|
@ -175,8 +174,8 @@ class WallabagRestController extends FOSRestController
|
|||
$this->validateUserAccess($entry->getUser()->getId());
|
||||
|
||||
$title = $request->request->get('title');
|
||||
$isArchived = $request->request->get('is_archived');
|
||||
$isStarred = $request->request->get('is_starred');
|
||||
$isArchived = $request->request->get('archive');
|
||||
$isStarred = $request->request->get('star');
|
||||
|
||||
if (!is_null($title)) {
|
||||
$entry->setTitle($title);
|
||||
|
@ -311,7 +310,12 @@ class WallabagRestController extends FOSRestController
|
|||
public function getTagsAction()
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
$json = $this->get('serializer')->serialize($this->getUser()->getTags(), 'json');
|
||||
|
||||
$tags = $this->getDoctrine()
|
||||
->getRepository('WallabagCoreBundle:Tag')
|
||||
->findAllTags($this->getUser()->getId());
|
||||
|
||||
$json = $this->get('serializer')->serialize($tags, 'json');
|
||||
|
||||
return $this->renderJsonResponse($json);
|
||||
}
|
||||
|
@ -328,11 +332,10 @@ class WallabagRestController extends FOSRestController
|
|||
public function deleteTagAction(Tag $tag)
|
||||
{
|
||||
$this->validateAuthentication();
|
||||
$this->validateUserAccess($tag->getUser()->getId());
|
||||
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$em->remove($tag);
|
||||
$em->flush();
|
||||
$this->getDoctrine()
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->removeTag($this->getUser()->getId(), $tag);
|
||||
|
||||
$json = $this->get('serializer')->serialize($tag, 'json');
|
||||
|
||||
|
|
|
@ -208,7 +208,7 @@ class WallabagRestControllerTest extends WallabagApiTestCase
|
|||
|
||||
$tags = array();
|
||||
foreach ($entry->getTags() as $tag) {
|
||||
$tags[] = array('id' => $tag->getId(), 'label' => $tag->getLabel());
|
||||
$tags[] = array('id' => $tag->getId(), 'label' => $tag->getLabel(), 'slug' => $tag->getSlug());
|
||||
}
|
||||
|
||||
$this->client->request('GET', '/api/entries/'.$entry->getId().'/tags');
|
||||
|
@ -309,5 +309,13 @@ class WallabagRestControllerTest extends WallabagApiTestCase
|
|||
|
||||
$this->assertArrayHasKey('label', $content);
|
||||
$this->assertEquals($tag['label'], $content['label']);
|
||||
$this->assertEquals($tag['slug'], $content['slug']);
|
||||
|
||||
$entries = $entry = $this->client->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findAllByTagId($this->user->getId(), $tag['id']);
|
||||
|
||||
$this->assertCount(0, $entries);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,11 @@ abstract class WallabagApiTestCase extends WebTestCase
|
|||
*/
|
||||
protected $client = null;
|
||||
|
||||
/**
|
||||
* @var \FOS\UserBundle\Model\UserInterface
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->client = $this->createAuthorizedClient();
|
||||
|
@ -31,8 +36,8 @@ abstract class WallabagApiTestCase extends WebTestCase
|
|||
$loginManager = $container->get('fos_user.security.login_manager');
|
||||
$firewallName = $container->getParameter('fos_user.firewall_name');
|
||||
|
||||
$user = $userManager->findUserBy(array('username' => 'admin'));
|
||||
$loginManager->loginUser($firewallName, $user);
|
||||
$this->user = $userManager->findUserBy(array('username' => 'admin'));
|
||||
$loginManager->loginUser($firewallName, $this->user);
|
||||
|
||||
// save the login token into the session and put it in a cookie
|
||||
$container->get('session')->set('_security_'.$firewallName, serialize($container->get('security.token_storage')->getToken()));
|
||||
|
|
|
@ -20,26 +20,24 @@ class TagController extends Controller
|
|||
*/
|
||||
public function addTagFormAction(Request $request, Entry $entry)
|
||||
{
|
||||
$tag = new Tag($this->getUser());
|
||||
$tag = new Tag();
|
||||
$form = $this->createForm(new NewTagType(), $tag);
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isValid()) {
|
||||
$existingTag = $this->getDoctrine()
|
||||
->getRepository('WallabagCoreBundle:Tag')
|
||||
->findOneByLabelAndUserId($tag->getLabel(), $this->getUser()->getId());
|
||||
->findOneByLabel($tag->getLabel());
|
||||
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
if (is_null($existingTag)) {
|
||||
$entry->addTag($tag);
|
||||
$em->persist($tag);
|
||||
} else {
|
||||
if (!$existingTag->hasEntry($entry)) {
|
||||
} elseif (!$existingTag->hasEntry($entry)) {
|
||||
$entry->addTag($existingTag);
|
||||
$em->persist($existingTag);
|
||||
}
|
||||
}
|
||||
|
||||
$em->flush();
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ use Doctrine\Common\DataFixtures\AbstractFixture;
|
|||
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
|
||||
use Doctrine\Common\Persistence\ObjectManager;
|
||||
use Wallabag\CoreBundle\Entity\Entry;
|
||||
use Wallabag\CoreBundle\Entity\Tag;
|
||||
|
||||
class LoadEntryData extends AbstractFixture implements OrderedFixtureInterface
|
||||
{
|
||||
|
@ -50,13 +49,8 @@ class LoadEntryData extends AbstractFixture implements OrderedFixtureInterface
|
|||
$entry3->setContent('This is my content /o/');
|
||||
$entry3->setLanguage('en');
|
||||
|
||||
$tag1 = new Tag($this->getReference('bob-user'));
|
||||
$tag1->setLabel('foo');
|
||||
$tag2 = new Tag($this->getReference('bob-user'));
|
||||
$tag2->setLabel('bar');
|
||||
|
||||
$entry3->addTag($tag1);
|
||||
$entry3->addTag($tag2);
|
||||
$entry3->addTag($this->getReference('foo-tag'));
|
||||
$entry3->addTag($this->getReference('bar-tag'));
|
||||
|
||||
$manager->persist($entry3);
|
||||
|
||||
|
@ -71,13 +65,8 @@ class LoadEntryData extends AbstractFixture implements OrderedFixtureInterface
|
|||
$entry4->setContent('This is my content /o/');
|
||||
$entry4->setLanguage('en');
|
||||
|
||||
$tag1 = new Tag($this->getReference('admin-user'));
|
||||
$tag1->setLabel('foo');
|
||||
$tag2 = new Tag($this->getReference('admin-user'));
|
||||
$tag2->setLabel('bar');
|
||||
|
||||
$entry4->addTag($tag1);
|
||||
$entry4->addTag($tag2);
|
||||
$entry4->addTag($this->getReference('foo-tag'));
|
||||
$entry4->addTag($this->getReference('bar-tag'));
|
||||
|
||||
$manager->persist($entry4);
|
||||
|
||||
|
|
41
src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTagData.php
Normal file
41
src/Wallabag/CoreBundle/DataFixtures/ORM/LoadTagData.php
Normal file
|
@ -0,0 +1,41 @@
|
|||
<?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\Tag;
|
||||
|
||||
class LoadTagData extends AbstractFixture implements OrderedFixtureInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function load(ObjectManager $manager)
|
||||
{
|
||||
$tag1 = new Tag();
|
||||
$tag1->setLabel('foo');
|
||||
|
||||
$manager->persist($tag1);
|
||||
|
||||
$this->addReference('foo-tag', $tag1);
|
||||
|
||||
$tag2 = new Tag();
|
||||
$tag2->setLabel('bar');
|
||||
|
||||
$manager->persist($tag2);
|
||||
|
||||
$this->addReference('bar-tag', $tag2);
|
||||
|
||||
$manager->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getOrder()
|
||||
{
|
||||
return 25;
|
||||
}
|
||||
}
|
|
@ -465,7 +465,7 @@ class Entry
|
|||
// check if tag already exist but has not yet be persisted
|
||||
// it seems that the previous condition with `contains()` doesn't check that case
|
||||
foreach ($this->tags as $existingTag) {
|
||||
if ($existingTag->getUser() !== $tag->getUser() || $existingTag->getLabel() === $tag->getLabel()) {
|
||||
if ($existingTag->getLabel() === $tag->getLabel()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ class Tag
|
|||
private $label;
|
||||
|
||||
/**
|
||||
* @Expose
|
||||
* @Gedmo\Slug(fields={"label"})
|
||||
* @ORM\Column(length=128, unique=true)
|
||||
*/
|
||||
|
@ -48,14 +49,8 @@ class Tag
|
|||
*/
|
||||
private $entries;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Wallabag\UserBundle\Entity\User", inversedBy="tags")
|
||||
*/
|
||||
private $user;
|
||||
|
||||
public function __construct(\Wallabag\UserBundle\Entity\User $user)
|
||||
public function __construct()
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->entries = new ArrayCollection();
|
||||
}
|
||||
|
||||
|
@ -112,12 +107,4 @@ class Tag
|
|||
{
|
||||
return $this->entries->contains($entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ class RuleBasedTagger
|
|||
}
|
||||
|
||||
foreach ($rule->getTags() as $label) {
|
||||
$tag = $this->getTag($entry->getUser(), $label);
|
||||
$tag = $this->getTag($label);
|
||||
|
||||
$entry->addTag($tag);
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ class RuleBasedTagger
|
|||
|
||||
foreach ($entries as $entry) {
|
||||
foreach ($rule->getTags() as $label) {
|
||||
$tag = $this->getTag($user, $label);
|
||||
$tag = $this->getTag($label);
|
||||
|
||||
$entry->addTag($tag);
|
||||
}
|
||||
|
@ -73,19 +73,18 @@ class RuleBasedTagger
|
|||
}
|
||||
|
||||
/**
|
||||
* Fetch a tag for a user.
|
||||
* Fetch a tag.
|
||||
*
|
||||
* @param User $user
|
||||
* @param string $label The tag's label.
|
||||
*
|
||||
* @return Tag
|
||||
*/
|
||||
private function getTag(User $user, $label)
|
||||
private function getTag($label)
|
||||
{
|
||||
$tag = $this->tagRepository->findOneByLabelAndUserId($label, $user->getId());
|
||||
$tag = $this->tagRepository->findOneByLabel($label);
|
||||
|
||||
if (!$tag) {
|
||||
$tag = new Tag($user);
|
||||
$tag = new Tag();
|
||||
$tag->setLabel($label);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ namespace Wallabag\CoreBundle\Repository;
|
|||
use Doctrine\ORM\EntityRepository;
|
||||
use Pagerfanta\Adapter\DoctrineORMAdapter;
|
||||
use Pagerfanta\Pagerfanta;
|
||||
use Wallabag\CoreBundle\Entity\Tag;
|
||||
|
||||
class EntryRepository extends EntityRepository
|
||||
{
|
||||
|
@ -179,4 +180,47 @@ class EntryRepository extends EntityRepository
|
|||
->getQuery()
|
||||
->getSingleResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a tag from all user entries.
|
||||
*
|
||||
* We need to loop on each entry attached to the given tag to remove it, since Doctrine doesn't know EntryTag entity because it's a ManyToMany relation.
|
||||
* It could be faster with one query but I don't know how to retrieve the table name `entry_tag` which can have a prefix:
|
||||
*
|
||||
* DELETE et FROM entry_tag et WHERE et.entry_id IN ( SELECT e.id FROM entry e WHERE e.user_id = :userId ) AND et.tag_id = :tagId
|
||||
*
|
||||
* @param int $userId
|
||||
* @param Tag $tag
|
||||
*/
|
||||
public function removeTag($userId, Tag $tag)
|
||||
{
|
||||
$entries = $this->getBuilderByUser($userId)
|
||||
->innerJoin('e.tags', 't')
|
||||
->andWhere('t.id = :tagId')->setParameter('tagId', $tag->getId())
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
foreach ($entries as $entry) {
|
||||
$entry->removeTag($tag);
|
||||
}
|
||||
|
||||
$this->getEntityManager()->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all entries that are attached to a give tag id.
|
||||
*
|
||||
* @param int $userId
|
||||
* @param int $tagId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findAllByTagId($userId, $tagId)
|
||||
{
|
||||
return $this->getBuilderByUser($userId)
|
||||
->innerJoin('e.tags', 't')
|
||||
->andWhere('t.id = :tagId')->setParameter('tagId', $tagId)
|
||||
->getQuery()
|
||||
->getResult();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,16 +9,29 @@ use Pagerfanta\Pagerfanta;
|
|||
class TagRepository extends EntityRepository
|
||||
{
|
||||
/**
|
||||
* Find Tags.
|
||||
* Return only the QueryBuilder to retrieve all tags for a given user.
|
||||
*
|
||||
* @param int $userId
|
||||
*
|
||||
* @return array
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
private function getQbForAllTags($userId)
|
||||
{
|
||||
return $this->createQueryBuilder('t')
|
||||
->leftJoin('t.entries', 'e')
|
||||
->where('e.user = :userId')->setParameter('userId', $userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find Tags and return a Pager.
|
||||
*
|
||||
* @param int $userId
|
||||
*
|
||||
* @return Pagerfanta
|
||||
*/
|
||||
public function findTags($userId)
|
||||
{
|
||||
$qb = $this->createQueryBuilder('t')
|
||||
->where('t.user =:userId')->setParameter('userId', $userId);
|
||||
$qb = $this->getQbForAllTags($userId);
|
||||
|
||||
$pagerAdapter = new DoctrineORMAdapter($qb);
|
||||
|
||||
|
@ -26,19 +39,16 @@ class TagRepository extends EntityRepository
|
|||
}
|
||||
|
||||
/**
|
||||
* Find a tag by its label and its owner.
|
||||
* Find Tags.
|
||||
*
|
||||
* @param string $label
|
||||
* @param int $userId
|
||||
*
|
||||
* @return Tag|null
|
||||
* @return array
|
||||
*/
|
||||
public function findOneByLabelAndUserId($label, $userId)
|
||||
public function findAllTags($userId)
|
||||
{
|
||||
return $this->createQueryBuilder('t')
|
||||
->where('t.label = :label')->setParameter('label', $label)
|
||||
->andWhere('t.user = :user_id')->setParameter('user_id', $userId)
|
||||
return $this->getQbForAllTags($userId)
|
||||
->getQuery()
|
||||
->getOneOrNullResult();
|
||||
->getResult();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,9 +69,7 @@ class RuleBasedTaggerTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
$tags = $entry->getTags();
|
||||
$this->assertSame('foo', $tags[0]->getLabel());
|
||||
$this->assertSame($user, $tags[0]->getUser());
|
||||
$this->assertSame('bar', $tags[1]->getLabel());
|
||||
$this->assertSame($user, $tags[1]->getUser());
|
||||
}
|
||||
|
||||
public function testTagWithAMixOfMatchingRules()
|
||||
|
@ -92,7 +90,6 @@ class RuleBasedTaggerTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
$tags = $entry->getTags();
|
||||
$this->assertSame('foo', $tags[0]->getLabel());
|
||||
$this->assertSame($user, $tags[0]->getUser());
|
||||
}
|
||||
|
||||
public function testWhenTheTagExists()
|
||||
|
@ -100,7 +97,7 @@ class RuleBasedTaggerTest extends \PHPUnit_Framework_TestCase
|
|||
$taggingRule = $this->getTaggingRule('rule as string', array('foo'));
|
||||
$user = $this->getUser([$taggingRule]);
|
||||
$entry = new Entry($user);
|
||||
$tag = new Tag($user);
|
||||
$tag = new Tag();
|
||||
|
||||
$this->rulerz
|
||||
->expects($this->once())
|
||||
|
@ -110,7 +107,9 @@ class RuleBasedTaggerTest extends \PHPUnit_Framework_TestCase
|
|||
|
||||
$this->tagRepository
|
||||
->expects($this->once())
|
||||
->method('findOneByLabelAndUserId')
|
||||
// the method `findOneByLabel` doesn't exist, EntityRepository will then call `_call` method
|
||||
// to magically call the `findOneBy` with ['label' => 'foo']
|
||||
->method('__call')
|
||||
->willReturn($tag);
|
||||
|
||||
$this->tagger->tag($entry);
|
||||
|
|
|
@ -13,7 +13,6 @@ use JMS\Serializer\Annotation\Expose;
|
|||
use FOS\UserBundle\Model\User as BaseUser;
|
||||
use Wallabag\CoreBundle\Entity\Config;
|
||||
use Wallabag\CoreBundle\Entity\Entry;
|
||||
use Wallabag\CoreBundle\Entity\Tag;
|
||||
|
||||
/**
|
||||
* User.
|
||||
|
@ -69,11 +68,6 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
|
|||
*/
|
||||
protected $config;
|
||||
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity="Wallabag\CoreBundle\Entity\Tag", mappedBy="user", cascade={"remove"})
|
||||
*/
|
||||
protected $tags;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="integer", nullable=true)
|
||||
*/
|
||||
|
@ -94,7 +88,6 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
|
|||
{
|
||||
parent::__construct();
|
||||
$this->entries = new ArrayCollection();
|
||||
$this->tags = new ArrayCollection();
|
||||
$this->roles = array('ROLE_USER');
|
||||
}
|
||||
|
||||
|
@ -171,26 +164,6 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
|
|||
return $this->entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Entry $entry
|
||||
*
|
||||
* @return User
|
||||
*/
|
||||
public function addTag(Tag $tag)
|
||||
{
|
||||
$this->tags[] = $tag;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArrayCollection<Tag>
|
||||
*/
|
||||
public function getTags()
|
||||
{
|
||||
return $this->tags;
|
||||
}
|
||||
|
||||
public function isEqualTo(UserInterface $user)
|
||||
{
|
||||
return $this->username === $user->getUsername();
|
||||
|
|
Loading…
Reference in a new issue