diff options
9 files changed, 162 insertions, 45 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/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.de.yml b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.de.yml index f57db303..a066c8e3 100644 --- a/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.de.yml +++ b/app/Resources/CraueConfigBundle/translations/CraueConfigBundle.de.yml | |||
@@ -1,36 +1,36 @@ | |||
1 | # settings_changed: Configuration updated | 1 | settings_changed: 'Konfiguration aktualisiert' |
2 | download_pictures: Bilder auf den Server herunterladen | 2 | download_pictures: 'Bilder auf den Server herunterladen' |
3 | carrot: Teilen zu Carrot aktivieren | 3 | carrot: 'Teilen zu Carrot aktivieren' |
4 | diaspora_url: Diaspora-URL, sofern der Service aktiviert ist | 4 | diaspora_url: 'Diaspora-URL, sofern der Service aktiviert ist' |
5 | export_epub: ePUB-Export aktivieren | 5 | export_epub: 'ePUB-Export aktivieren' |
6 | export_mobi: mobi-Export aktivieren | 6 | export_mobi: 'mobi-Export aktivieren' |
7 | export_pdf: PDF-Export aktivieren | 7 | export_pdf: 'PDF-Export aktivieren' |
8 | export_csv: CSV-Export aktivieren | 8 | export_csv: 'CSV-Export aktivieren' |
9 | export_json: JSON-Export aktivieren | 9 | export_json: 'JSON-Export aktivieren' |
10 | export_txt: TXT-Export aktivieren | 10 | export_txt: 'TXT-Export aktivieren' |
11 | export_xml: XML-Export aktivieren | 11 | export_xml: 'XML-Export aktivieren' |
12 | import_with_rabbitmq: Aktiviere RabbitMQ, um Artikel asynchron zu importieren | 12 | import_with_rabbitmq: 'Aktiviere RabbitMQ, um Artikel asynchron zu importieren' |
13 | import_with_redis: Aktiviere Redis, um Artikel asynchron zu importieren | 13 | import_with_redis: 'Aktiviere Redis, um Artikel asynchron zu importieren' |
14 | shaarli_url: Shaarli-URL, sofern der Service aktiviert ist | 14 | shaarli_url: 'Shaarli-URL, sofern der Service aktiviert ist' |
15 | share_diaspora: Teilen zu Diaspora aktiveren | 15 | share_diaspora: 'Teilen zu Diaspora aktiveren' |
16 | share_mail: Teilen via E-Mail aktiveren | 16 | share_mail: 'Teilen via E-Mail aktiveren' |
17 | share_shaarli: Teilen zu Shaarli aktiveren | 17 | share_shaarli: 'Teilen zu Shaarli aktiveren' |
18 | share_scuttle: Teilen zu Scuttle aktiveren | 18 | share_twitter: 'Teilen zu Twitter aktiveren' |
19 | share_twitter: Teilen zu Twitter aktiveren | 19 | share_unmark: 'Teilen zu Unmark.it aktiveren' |
20 | share_unmark: Teilen zu Unmark.it aktiveren | 20 | show_printlink: 'Link anzeigen, um den Inhalt auszudrucken' |
21 | show_printlink: Link anzeigen, um den Inhalt auszudrucken | 21 | wallabag_support_url: 'Support-URL für wallabag' |
22 | wallabag_support_url: Support-URL für wallabag | 22 | wallabag_url: 'URL von *deiner* wallabag-Instanz' |
23 | entry: "Artikel" | 23 | entry: 'Artikel' |
24 | export: "Export" | 24 | export: 'Export' |
25 | import: "Import" | 25 | import: 'Import' |
26 | misc: "Verschiedenes" | 26 | misc: 'Verschiedenes' |
27 | modify_settings: "Übernehmen" | 27 | modify_settings: 'Übernehmen' |
28 | piwik_host: Host deiner Webseite in Piwik (ohne http:// oder https://) | 28 | piwik_host: 'Host deiner Webseite in Piwik (ohne http:// oder https://)' |
29 | piwik_site_id: ID deiner Webseite in Piwik | 29 | piwik_site_id: 'ID deiner Webseite in Piwik' |
30 | piwik_enabled: Piwik aktivieren | 30 | piwik_enabled: 'Piwik aktivieren' |
31 | demo_mode_enabled: "Test-Modus aktivieren? (nur für die öffentliche wallabag-Demo genutzt)" | 31 | demo_mode_enabled: 'Test-Modus aktivieren? (nur für die öffentliche wallabag-Demo genutzt)' |
32 | demo_mode_username: "Test-Benutzer" | 32 | demo_mode_username: 'Test-Benutzer' |
33 | share_public: Erlaube eine öffentliche URL für Einträge | 33 | share_public: 'Erlaube eine öffentliche URL für Einträge' |
34 | # download_images_enabled: Download images locally | 34 | download_images_enabled: 'Bilder lokal herunterladen' |
35 | # restricted_access: Enable authentication for websites with paywall | 35 | restricted_access: 'Authentifizierung für Webseiten mit Paywall aktivieren' |
36 | # api_user_registration: Enable user to be registered using the API | 36 | api_user_registration: 'Registrierung eines Benutzers über die API ermöglichen' |
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/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig index 6424df8d..12cead48 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/baggy/Entry/entries.html.twig | |||
@@ -86,7 +86,7 @@ | |||
86 | 86 | ||
87 | <!-- Export --> | 87 | <!-- Export --> |
88 | <aside id="download-form"> | 88 | <aside id="download-form"> |
89 | {% set currentTag = '' %} | 89 | {% set currentTag = null %} |
90 | {% if tag is defined %} | 90 | {% if tag is defined %} |
91 | {% set currentTag = tag %} | 91 | {% set currentTag = tag %} |
92 | {% endif %} | 92 | {% endif %} |
diff --git a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig index 0c4dc80b..9d6fb3f5 100644 --- a/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig +++ b/src/Wallabag/CoreBundle/Resources/views/themes/material/Entry/entries.html.twig | |||
@@ -57,7 +57,7 @@ | |||
57 | 57 | ||
58 | <!-- Export --> | 58 | <!-- Export --> |
59 | <div id="export" class="side-nav right-aligned"> | 59 | <div id="export" class="side-nav right-aligned"> |
60 | {% set currentTag = '' %} | 60 | {% set currentTag = null %} |
61 | {% if tag is defined %} | 61 | {% if tag is defined %} |
62 | {% set currentTag = tag.slug %} | 62 | {% set currentTag = tag.slug %} |
63 | {% endif %} | 63 | {% endif %} |
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() |