From a991c46eedec0efb24d0a9974b1c7fcabf8cfa66 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Fran=C3=A7ois=20D?= Date: Wed, 23 Aug 2017 23:06:40 +0200 Subject: [PATCH] Set a starred_at field when an entry is starred. This date is used to sort starred entries. Can not use Entry::timestamps method otherwise starred_at will be updated each time entry is updated. Add an updateStar method into Entry class A migration script has been added in order to set starred_at field. --- .../Version20170824113337.php | 63 +++++++++++++++++++ .../Controller/EntryRestController.php | 4 +- .../CoreBundle/Controller/EntryController.php | 1 + src/Wallabag/CoreBundle/Entity/Entry.php | 47 ++++++++++++++ .../CoreBundle/Repository/EntryRepository.php | 11 ++-- .../Controller/EntryRestControllerTest.php | 5 ++ 6 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 app/DoctrineMigrations/Version20170824113337.php diff --git a/app/DoctrineMigrations/Version20170824113337.php b/app/DoctrineMigrations/Version20170824113337.php new file mode 100644 index 00000000..7393d683 --- /dev/null +++ b/app/DoctrineMigrations/Version20170824113337.php @@ -0,0 +1,63 @@ +container = $container; + } + + /** + * @param Schema $schema + */ + public function up(Schema $schema) + { + $entryTable = $schema->getTable($this->getTable('entry')); + + $this->skipIf($entryTable->hasColumn('starred_at'), 'It seems that you already played this migration.'); + + $entryTable->addColumn('starred_at', 'datetime', [ + 'notnull' => false, + ]); + } + + public function postUp(Schema $schema) + { + $entryTable = $schema->getTable($this->getTable('entry')); + $this->skipIf(!$entryTable->hasColumn('starred_at'), 'Unable to add starred_at colum'); + + $this->connection->executeQuery('UPDATE ' . $this->getTable('entry') . ' SET starred_at = updated_at WHERE is_starred = true'); + } + + /** + * @param Schema $schema + */ + public function down(Schema $schema) + { + $entryTable = $schema->getTable($this->getTable('entry')); + + $this->skipIf(!$entryTable->hasColumn('starred_at'), 'It seems that you already played this migration.'); + + $entryTable->dropColumn('starred_at'); + } + + private function getTable($tableName) + { + return $this->container->getParameter('database_table_prefix') . $tableName; + } +} diff --git a/src/Wallabag/ApiBundle/Controller/EntryRestController.php b/src/Wallabag/ApiBundle/Controller/EntryRestController.php index bc1b6f92..6db97731 100644 --- a/src/Wallabag/ApiBundle/Controller/EntryRestController.php +++ b/src/Wallabag/ApiBundle/Controller/EntryRestController.php @@ -361,7 +361,7 @@ class EntryRestController extends WallabagRestController } if (null !== $data['isStarred']) { - $entry->setStarred((bool) $data['isStarred']); + $entry->updateStar((bool) $data['isStarred']); } if (!empty($data['tags'])) { @@ -464,7 +464,7 @@ class EntryRestController extends WallabagRestController } if (null !== $data['isStarred']) { - $entry->setStarred((bool) $data['isStarred']); + $entry->updateStar((bool) $data['isStarred']); } if (!empty($data['tags'])) { diff --git a/src/Wallabag/CoreBundle/Controller/EntryController.php b/src/Wallabag/CoreBundle/Controller/EntryController.php index 3dcfbebe..b0b74c38 100644 --- a/src/Wallabag/CoreBundle/Controller/EntryController.php +++ b/src/Wallabag/CoreBundle/Controller/EntryController.php @@ -333,6 +333,7 @@ class EntryController extends Controller $this->checkUserAction($entry); $entry->toggleStar(); + $entry->updateStar($entry->isStarred()); $this->getDoctrine()->getManager()->flush(); $message = 'flashes.entry.notice.entry_unstarred'; diff --git a/src/Wallabag/CoreBundle/Entity/Entry.php b/src/Wallabag/CoreBundle/Entity/Entry.php index 61d01bdc..4367902e 100644 --- a/src/Wallabag/CoreBundle/Entity/Entry.php +++ b/src/Wallabag/CoreBundle/Entity/Entry.php @@ -142,6 +142,15 @@ class Entry */ private $publishedBy; + /** + * @var \DateTime + * + * @ORM\Column(name="starred_at", type="datetime", nullable=true) + * + * @Groups({"entries_for_user", "export_all"}) + */ + private $starredAt = null; + /** * @ORM\OneToMany(targetEntity="Wallabag\AnnotationBundle\Entity\Annotation", mappedBy="entry", cascade={"persist", "remove"}) * @ORM\JoinTable @@ -475,6 +484,44 @@ class Entry return $this->updatedAt; } + /** + * @return \DateTime|null + */ + public function getStarredAt() + { + return $this->starredAt; + } + + /** + * @param \DateTime|null $starredAt + * + * @return Entry + */ + public function setStarredAt($starredAt = null) + { + $this->starredAt = $starredAt; + + return $this; + } + + /** + * update isStarred and starred_at fields. + * + * @param bool $isStarred + * + * @return Entry + */ + public function updateStar($isStarred = false) + { + $this->setStarred($isStarred); + $this->setStarredAt(null); + if ($this->isStarred()) { + $this->setStarredAt(new \DateTime()); + } + + return $this; + } + /** * @return ArrayCollection */ diff --git a/src/Wallabag/CoreBundle/Repository/EntryRepository.php b/src/Wallabag/CoreBundle/Repository/EntryRepository.php index eb5e3205..ecc159fc 100644 --- a/src/Wallabag/CoreBundle/Repository/EntryRepository.php +++ b/src/Wallabag/CoreBundle/Repository/EntryRepository.php @@ -65,7 +65,7 @@ class EntryRepository extends EntityRepository public function getBuilderForStarredByUser($userId) { return $this - ->getBuilderByUser($userId) + ->getBuilderByUser($userId, 'starredAt', 'desc') ->andWhere('e.isStarred = true') ; } @@ -401,15 +401,16 @@ class EntryRepository extends EntityRepository /** * Return a query builder to used by other getBuilderFor* method. * - * @param int $userId + * @param int $userId + * @param string $sortBy + * @param string $direction * * @return QueryBuilder */ - private function getBuilderByUser($userId) + private function getBuilderByUser($userId, $sortBy = 'createdAt', $direction = 'desc') { return $this->createQueryBuilder('e') ->andWhere('e.user = :userId')->setParameter('userId', $userId) - ->orderBy('e.createdAt', 'desc') - ; + ->orderBy(sprintf('e.%s', $sortBy), $direction); } } diff --git a/tests/Wallabag/ApiBundle/Controller/EntryRestControllerTest.php b/tests/Wallabag/ApiBundle/Controller/EntryRestControllerTest.php index 2dc08be2..f4c8a630 100644 --- a/tests/Wallabag/ApiBundle/Controller/EntryRestControllerTest.php +++ b/tests/Wallabag/ApiBundle/Controller/EntryRestControllerTest.php @@ -407,6 +407,7 @@ class EntryRestControllerTest extends WallabagApiTestCase $this->assertSame('http://www.lemonde.fr/pixels/article/2015/03/28/plongee-dans-l-univers-d-ingress-le-jeu-de-google-aux-frontieres-du-reel_4601155_4408996.html', $content['url']); $this->assertSame(0, $content['is_archived']); $this->assertSame(0, $content['is_starred']); + $this->assertNull($content['starred_at']); $this->assertSame('New title for my article', $content['title']); $this->assertSame(1, $content['user_id']); $this->assertCount(2, $content['tags']); @@ -483,6 +484,7 @@ class EntryRestControllerTest extends WallabagApiTestCase public function testPostArchivedAndStarredEntry() { + $now = new \DateTime(); $this->client->request('POST', '/api/entries.json', [ 'url' => 'http://www.lemonde.fr/idees/article/2016/02/08/preserver-la-liberte-d-expression-sur-les-reseaux-sociaux_4861503_3232.html', 'archive' => '1', @@ -497,6 +499,7 @@ class EntryRestControllerTest extends WallabagApiTestCase $this->assertSame('http://www.lemonde.fr/idees/article/2016/02/08/preserver-la-liberte-d-expression-sur-les-reseaux-sociaux_4861503_3232.html', $content['url']); $this->assertSame(1, $content['is_archived']); $this->assertSame(1, $content['is_starred']); + $this->assertGreaterThanOrEqual($now->getTimestamp(), (new \DateTime($content['starred_at']))->getTimestamp()); $this->assertSame(1, $content['user_id']); } @@ -753,6 +756,7 @@ class EntryRestControllerTest extends WallabagApiTestCase public function testSaveIsStarredAfterPatch() { + $now = new \DateTime(); $entry = $this->client->getContainer() ->get('doctrine.orm.entity_manager') ->getRepository('WallabagCoreBundle:Entry') @@ -770,6 +774,7 @@ class EntryRestControllerTest extends WallabagApiTestCase $content = json_decode($this->client->getResponse()->getContent(), true); $this->assertSame(1, $content['is_starred']); + $this->assertGreaterThanOrEqual($now->getTimestamp(), (new \DateTime($content['starred_at']))->getTimestamp()); } public function dataForEntriesExistWithUrl() -- 2.41.0