diff options
author | François D <franek@users.noreply.github.com> | 2017-08-23 23:06:40 +0200 |
---|---|---|
committer | François D <franek@users.noreply.github.com> | 2017-08-25 21:19:47 +0200 |
commit | a991c46eedec0efb24d0a9974b1c7fcabf8cfa66 (patch) | |
tree | fa33236c5ef67e023833c889eb52d5bed99d35bd | |
parent | 2490f61dca635026a3eb9b5e9b6978b1981b1172 (diff) | |
download | wallabag-a991c46eedec0efb24d0a9974b1c7fcabf8cfa66.tar.gz wallabag-a991c46eedec0efb24d0a9974b1c7fcabf8cfa66.tar.zst wallabag-a991c46eedec0efb24d0a9974b1c7fcabf8cfa66.zip |
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.
6 files changed, 124 insertions, 7 deletions
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 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Application\Migrations; | ||
4 | |||
5 | use Doctrine\DBAL\Migrations\AbstractMigration; | ||
6 | use Doctrine\DBAL\Schema\Schema; | ||
7 | use Symfony\Component\DependencyInjection\ContainerAwareInterface; | ||
8 | use Symfony\Component\DependencyInjection\ContainerInterface; | ||
9 | |||
10 | /** | ||
11 | * Add starred_at column and set its value to updated_at for is_starred entries. | ||
12 | */ | ||
13 | class Version20170824113337 extends AbstractMigration implements ContainerAwareInterface | ||
14 | { | ||
15 | /** | ||
16 | * @var ContainerInterface | ||
17 | */ | ||
18 | private $container; | ||
19 | |||
20 | public function setContainer(ContainerInterface $container = null) | ||
21 | { | ||
22 | $this->container = $container; | ||
23 | } | ||
24 | |||
25 | /** | ||
26 | * @param Schema $schema | ||
27 | */ | ||
28 | public function up(Schema $schema) | ||
29 | { | ||
30 | $entryTable = $schema->getTable($this->getTable('entry')); | ||
31 | |||
32 | $this->skipIf($entryTable->hasColumn('starred_at'), 'It seems that you already played this migration.'); | ||
33 | |||
34 | $entryTable->addColumn('starred_at', 'datetime', [ | ||
35 | 'notnull' => false, | ||
36 | ]); | ||
37 | } | ||
38 | |||
39 | public function postUp(Schema $schema) | ||
40 | { | ||
41 | $entryTable = $schema->getTable($this->getTable('entry')); | ||
42 | $this->skipIf(!$entryTable->hasColumn('starred_at'), 'Unable to add starred_at colum'); | ||
43 | |||
44 | $this->connection->executeQuery('UPDATE ' . $this->getTable('entry') . ' SET starred_at = updated_at WHERE is_starred = true'); | ||
45 | } | ||
46 | |||
47 | /** | ||
48 | * @param Schema $schema | ||
49 | */ | ||
50 | public function down(Schema $schema) | ||
51 | { | ||
52 | $entryTable = $schema->getTable($this->getTable('entry')); | ||
53 | |||
54 | $this->skipIf(!$entryTable->hasColumn('starred_at'), 'It seems that you already played this migration.'); | ||
55 | |||
56 | $entryTable->dropColumn('starred_at'); | ||
57 | } | ||
58 | |||
59 | private function getTable($tableName) | ||
60 | { | ||
61 | return $this->container->getParameter('database_table_prefix') . $tableName; | ||
62 | } | ||
63 | } | ||
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 | |||
361 | } | 361 | } |
362 | 362 | ||
363 | if (null !== $data['isStarred']) { | 363 | if (null !== $data['isStarred']) { |
364 | $entry->setStarred((bool) $data['isStarred']); | 364 | $entry->updateStar((bool) $data['isStarred']); |
365 | } | 365 | } |
366 | 366 | ||
367 | if (!empty($data['tags'])) { | 367 | if (!empty($data['tags'])) { |
@@ -464,7 +464,7 @@ class EntryRestController extends WallabagRestController | |||
464 | } | 464 | } |
465 | 465 | ||
466 | if (null !== $data['isStarred']) { | 466 | if (null !== $data['isStarred']) { |
467 | $entry->setStarred((bool) $data['isStarred']); | 467 | $entry->updateStar((bool) $data['isStarred']); |
468 | } | 468 | } |
469 | 469 | ||
470 | if (!empty($data['tags'])) { | 470 | 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 | |||
333 | $this->checkUserAction($entry); | 333 | $this->checkUserAction($entry); |
334 | 334 | ||
335 | $entry->toggleStar(); | 335 | $entry->toggleStar(); |
336 | $entry->updateStar($entry->isStarred()); | ||
336 | $this->getDoctrine()->getManager()->flush(); | 337 | $this->getDoctrine()->getManager()->flush(); |
337 | 338 | ||
338 | $message = 'flashes.entry.notice.entry_unstarred'; | 339 | $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 | |||
@@ -143,6 +143,15 @@ class Entry | |||
143 | private $publishedBy; | 143 | private $publishedBy; |
144 | 144 | ||
145 | /** | 145 | /** |
146 | * @var \DateTime | ||
147 | * | ||
148 | * @ORM\Column(name="starred_at", type="datetime", nullable=true) | ||
149 | * | ||
150 | * @Groups({"entries_for_user", "export_all"}) | ||
151 | */ | ||
152 | private $starredAt = null; | ||
153 | |||
154 | /** | ||
146 | * @ORM\OneToMany(targetEntity="Wallabag\AnnotationBundle\Entity\Annotation", mappedBy="entry", cascade={"persist", "remove"}) | 155 | * @ORM\OneToMany(targetEntity="Wallabag\AnnotationBundle\Entity\Annotation", mappedBy="entry", cascade={"persist", "remove"}) |
147 | * @ORM\JoinTable | 156 | * @ORM\JoinTable |
148 | * | 157 | * |
@@ -476,6 +485,44 @@ class Entry | |||
476 | } | 485 | } |
477 | 486 | ||
478 | /** | 487 | /** |
488 | * @return \DateTime|null | ||
489 | */ | ||
490 | public function getStarredAt() | ||
491 | { | ||
492 | return $this->starredAt; | ||
493 | } | ||
494 | |||
495 | /** | ||
496 | * @param \DateTime|null $starredAt | ||
497 | * | ||
498 | * @return Entry | ||
499 | */ | ||
500 | public function setStarredAt($starredAt = null) | ||
501 | { | ||
502 | $this->starredAt = $starredAt; | ||
503 | |||
504 | return $this; | ||
505 | } | ||
506 | |||
507 | /** | ||
508 | * update isStarred and starred_at fields. | ||
509 | * | ||
510 | * @param bool $isStarred | ||
511 | * | ||
512 | * @return Entry | ||
513 | */ | ||
514 | public function updateStar($isStarred = false) | ||
515 | { | ||
516 | $this->setStarred($isStarred); | ||
517 | $this->setStarredAt(null); | ||
518 | if ($this->isStarred()) { | ||
519 | $this->setStarredAt(new \DateTime()); | ||
520 | } | ||
521 | |||
522 | return $this; | ||
523 | } | ||
524 | |||
525 | /** | ||
479 | * @return ArrayCollection<Annotation> | 526 | * @return ArrayCollection<Annotation> |
480 | */ | 527 | */ |
481 | public function getAnnotations() | 528 | public function getAnnotations() |
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 | |||
65 | public function getBuilderForStarredByUser($userId) | 65 | public function getBuilderForStarredByUser($userId) |
66 | { | 66 | { |
67 | return $this | 67 | return $this |
68 | ->getBuilderByUser($userId) | 68 | ->getBuilderByUser($userId, 'starredAt', 'desc') |
69 | ->andWhere('e.isStarred = true') | 69 | ->andWhere('e.isStarred = true') |
70 | ; | 70 | ; |
71 | } | 71 | } |
@@ -401,15 +401,16 @@ class EntryRepository extends EntityRepository | |||
401 | /** | 401 | /** |
402 | * Return a query builder to used by other getBuilderFor* method. | 402 | * Return a query builder to used by other getBuilderFor* method. |
403 | * | 403 | * |
404 | * @param int $userId | 404 | * @param int $userId |
405 | * @param string $sortBy | ||
406 | * @param string $direction | ||
405 | * | 407 | * |
406 | * @return QueryBuilder | 408 | * @return QueryBuilder |
407 | */ | 409 | */ |
408 | private function getBuilderByUser($userId) | 410 | private function getBuilderByUser($userId, $sortBy = 'createdAt', $direction = 'desc') |
409 | { | 411 | { |
410 | return $this->createQueryBuilder('e') | 412 | return $this->createQueryBuilder('e') |
411 | ->andWhere('e.user = :userId')->setParameter('userId', $userId) | 413 | ->andWhere('e.user = :userId')->setParameter('userId', $userId) |
412 | ->orderBy('e.createdAt', 'desc') | 414 | ->orderBy(sprintf('e.%s', $sortBy), $direction); |
413 | ; | ||
414 | } | 415 | } |
415 | } | 416 | } |
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 | |||
407 | $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']); | 407 | $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']); |
408 | $this->assertSame(0, $content['is_archived']); | 408 | $this->assertSame(0, $content['is_archived']); |
409 | $this->assertSame(0, $content['is_starred']); | 409 | $this->assertSame(0, $content['is_starred']); |
410 | $this->assertNull($content['starred_at']); | ||
410 | $this->assertSame('New title for my article', $content['title']); | 411 | $this->assertSame('New title for my article', $content['title']); |
411 | $this->assertSame(1, $content['user_id']); | 412 | $this->assertSame(1, $content['user_id']); |
412 | $this->assertCount(2, $content['tags']); | 413 | $this->assertCount(2, $content['tags']); |
@@ -483,6 +484,7 @@ class EntryRestControllerTest extends WallabagApiTestCase | |||
483 | 484 | ||
484 | public function testPostArchivedAndStarredEntry() | 485 | public function testPostArchivedAndStarredEntry() |
485 | { | 486 | { |
487 | $now = new \DateTime(); | ||
486 | $this->client->request('POST', '/api/entries.json', [ | 488 | $this->client->request('POST', '/api/entries.json', [ |
487 | 'url' => 'http://www.lemonde.fr/idees/article/2016/02/08/preserver-la-liberte-d-expression-sur-les-reseaux-sociaux_4861503_3232.html', | 489 | 'url' => 'http://www.lemonde.fr/idees/article/2016/02/08/preserver-la-liberte-d-expression-sur-les-reseaux-sociaux_4861503_3232.html', |
488 | 'archive' => '1', | 490 | 'archive' => '1', |
@@ -497,6 +499,7 @@ class EntryRestControllerTest extends WallabagApiTestCase | |||
497 | $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']); | 499 | $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']); |
498 | $this->assertSame(1, $content['is_archived']); | 500 | $this->assertSame(1, $content['is_archived']); |
499 | $this->assertSame(1, $content['is_starred']); | 501 | $this->assertSame(1, $content['is_starred']); |
502 | $this->assertGreaterThanOrEqual($now->getTimestamp(), (new \DateTime($content['starred_at']))->getTimestamp()); | ||
500 | $this->assertSame(1, $content['user_id']); | 503 | $this->assertSame(1, $content['user_id']); |
501 | } | 504 | } |
502 | 505 | ||
@@ -753,6 +756,7 @@ class EntryRestControllerTest extends WallabagApiTestCase | |||
753 | 756 | ||
754 | public function testSaveIsStarredAfterPatch() | 757 | public function testSaveIsStarredAfterPatch() |
755 | { | 758 | { |
759 | $now = new \DateTime(); | ||
756 | $entry = $this->client->getContainer() | 760 | $entry = $this->client->getContainer() |
757 | ->get('doctrine.orm.entity_manager') | 761 | ->get('doctrine.orm.entity_manager') |
758 | ->getRepository('WallabagCoreBundle:Entry') | 762 | ->getRepository('WallabagCoreBundle:Entry') |
@@ -770,6 +774,7 @@ class EntryRestControllerTest extends WallabagApiTestCase | |||
770 | $content = json_decode($this->client->getResponse()->getContent(), true); | 774 | $content = json_decode($this->client->getResponse()->getContent(), true); |
771 | 775 | ||
772 | $this->assertSame(1, $content['is_starred']); | 776 | $this->assertSame(1, $content['is_starred']); |
777 | $this->assertGreaterThanOrEqual($now->getTimestamp(), (new \DateTime($content['starred_at']))->getTimestamp()); | ||
773 | } | 778 | } |
774 | 779 | ||
775 | public function dataForEntriesExistWithUrl() | 780 | public function dataForEntriesExistWithUrl() |