]> git.immae.eu Git - github/wallabag/wallabag.git/commitdiff
Added route to list entries with annotations
authorNicolas Lœuillet <nicolas@loeuillet.org>
Mon, 20 Apr 2020 17:00:58 +0000 (19:00 +0200)
committerNicolas Lœuillet <nicolas@loeuillet.org>
Mon, 20 Apr 2020 17:00:58 +0000 (19:00 +0200)
23 files changed:
app/config/security.yml
src/Wallabag/CoreBundle/Controller/EntryController.php
src/Wallabag/CoreBundle/Controller/ExportController.php
src/Wallabag/CoreBundle/Repository/EntryRepository.php
src/Wallabag/CoreBundle/Resources/translations/messages.da.yml
src/Wallabag/CoreBundle/Resources/translations/messages.de.yml
src/Wallabag/CoreBundle/Resources/translations/messages.en.yml
src/Wallabag/CoreBundle/Resources/translations/messages.es.yml
src/Wallabag/CoreBundle/Resources/translations/messages.fa.yml
src/Wallabag/CoreBundle/Resources/translations/messages.fr.yml
src/Wallabag/CoreBundle/Resources/translations/messages.it.yml
src/Wallabag/CoreBundle/Resources/translations/messages.ja.yml
src/Wallabag/CoreBundle/Resources/translations/messages.oc.yml
src/Wallabag/CoreBundle/Resources/translations/messages.pl.yml
src/Wallabag/CoreBundle/Resources/translations/messages.pt.yml
src/Wallabag/CoreBundle/Resources/translations/messages.ro.yml
src/Wallabag/CoreBundle/Resources/translations/messages.ru.yml
src/Wallabag/CoreBundle/Resources/translations/messages.th.yml
src/Wallabag/CoreBundle/Resources/translations/messages.tr.yml
src/Wallabag/CoreBundle/Resources/translations/messages.zh.yml
src/Wallabag/CoreBundle/Resources/views/themes/common/Entry/_title.html.twig
src/Wallabag/CoreBundle/Resources/views/themes/material/layout.html.twig
src/Wallabag/CoreBundle/Twig/WallabagExtension.php

index 760b2550320868d185be60972455147cf6257bd4..894bb83f12b7127b9f874fb1157bbe1daaebe685 100644 (file)
@@ -69,11 +69,11 @@ security:
         - { path: ^/logout, roles: [IS_AUTHENTICATED_ANONYMOUSLY, IS_AUTHENTICATED_2FA_IN_PROGRESS] }
         - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
         - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
-        - { path: /(unread|starred|archive|all).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
+        - { path: /(unread|starred|archive|with_annotations|all).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
         - { path: ^/locale, role: IS_AUTHENTICATED_ANONYMOUSLY }
         - { path: /tags/(.*).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
         - { path: ^/feed, roles: IS_AUTHENTICATED_ANONYMOUSLY }
-        - { path: /(unread|starred|archive).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY } # For backwards compatibility
+        - { path: /(unread|starred|archive|with_annotations).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY } # For backwards compatibility
         - { path: ^/share, roles: IS_AUTHENTICATED_ANONYMOUSLY }
         - { path: ^/settings, roles: ROLE_SUPER_ADMIN }
         - { path: ^/annotations, roles: ROLE_USER }
index ba5bfbe2916540ca7f2564d2f06891b6acd96ead..2c4b5536edc634f1a41087a385222cf1859b0f13 100644 (file)
@@ -235,12 +235,26 @@ class EntryController extends Controller
         return $this->showEntries('untagged', $request, $page);
     }
 
+    /**
+     * Shows entries with annotations for current user.
+     *
+     * @param int $page
+     *
+     * @Route("/with_annotations/list/{page}", name="with_annotations", defaults={"page" = "1"})
+     *
+     * @return \Symfony\Component\HttpFoundation\Response
+     */
+    public function showWithAnnotationsEntriesAction(Request $request, $page)
+    {
+        return $this->showEntries('with_annotations', $request, $page);
+    }
+
     /**
      * Shows random entry depending on the given type.
      *
      * @param string $type
      *
-     * @Route("/{type}/random", name="random_entry", requirements={"type": "unread|starred|archive|untagged|all"})
+     * @Route("/{type}/random", name="random_entry", requirements={"type": "unread|starred|archive|untagged|with_annotations|all"})
      *
      * @return \Symfony\Component\HttpFoundation\RedirectResponse
      */
@@ -503,6 +517,9 @@ class EntryController extends Controller
             case 'archive':
                 $qb = $repository->getBuilderForArchiveByUser($this->getUser()->getId());
                 break;
+            case 'with_annotations':
+                $qb = $repository->getBuilderForAnnotationsByUser($this->getUser()->getId());
+                break;
             case 'unread':
                 $qb = $repository->getBuilderForUnreadByUser($this->getUser()->getId());
                 break;
index cec8d4999a621032cb3b6748ac30fe188a5d180c..8517e7a91763dd6b5761bdbfa89395a806087ea3 100644 (file)
@@ -47,7 +47,7 @@ class ExportController extends Controller
      *
      * @Route("/export/{category}.{format}", name="export_entries", requirements={
      *     "format": "epub|mobi|pdf|json|xml|txt|csv",
-     *     "category": "all|unread|starred|archive|tag_entries|untagged|search"
+     *     "category": "all|unread|starred|archive|tag_entries|untagged|search|with_annotations"
      * })
      *
      * @return \Symfony\Component\HttpFoundation\Response
@@ -80,6 +80,13 @@ class ExportController extends Controller
              ->getResult();
 
             $title = 'Search ' . $searchTerm;
+        } elseif ('with_annotations' === $category) {
+            $entries = $repository->getBuilderForAnnotationsByUser(
+                $this->getUser()->getId()
+            )->getQuery()
+             ->getResult();
+
+            $title = 'With annotations';
         } else {
             $entries = $repository
                 ->$methodBuilder($this->getUser()->getId())
index bfd079377ac783bdd4c2e0e2f84cb3f2e9d0496b..9f25ad4c030147bf5c241b26b5116f55fc0617ac 100644 (file)
@@ -115,6 +115,21 @@ class EntryRepository extends EntityRepository
         return $this->sortQueryBuilder($this->getRawBuilderForUntaggedByUser($userId));
     }
 
+    /**
+     * Retrieve entries with annotations for a user.
+     *
+     * @param int $userId
+     *
+     * @return QueryBuilder
+     */
+    public function getBuilderForAnnotationsByUser($userId)
+    {
+        return $this
+            ->getSortedQueryBuilderByUser($userId)
+            ->innerJoin('e.annotations', 'a')
+            ;
+    }
+
     /**
      * Retrieve untagged entries for a user.
      *
@@ -520,6 +535,10 @@ class EntryRepository extends EntityRepository
                 $qb->leftJoin('e.tags', 't');
                 $qb->andWhere('t.id is null');
                 break;
+            case 'with_annotations':
+                $qb->leftJoin('e.annotations', 'a');
+                $qb->andWhere('a.id is not null');
+                break;
         }
 
         $ids = $qb->getQuery()->getArrayResult();
index 4d5259797d2fad335a0d85b6c33f6e983e18ba4b..b233789f8c1c5b87289ae8b80614f793c355b9e3 100644 (file)
@@ -20,6 +20,7 @@ menu:
         starred: 'Favoritter'
         archive: 'Arkiv'
         all_articles: 'Alle artikler'
+        # with_annotations: 'With annotations'
         config: 'Opsætning'
         tags: 'Tags'
         # internal_settings: 'Internal Settings'
@@ -194,6 +195,7 @@ entry:
         # starred: 'Starred entries'
         # archived: 'Archived entries'
         # filtered: 'Filtered entries'
+        # with_annotations: 'Entries with annotations'
         # filtered_tags: 'Filtered by tags:'
         # filtered_search: 'Filtered by search:'
         # untagged: 'Untagged entries'
index cd70c99ffcc60f8b2604c4d5358d75c7d3852b7d..d955c046f0d9c593eda5d31c5c9e217d0b40a5ab 100644 (file)
@@ -20,6 +20,7 @@ menu:
         starred: 'Favoriten'
         archive: 'Archiv'
         all_articles: 'Alle Artikel'
+        # with_annotations: 'With annotations'
         config: 'Konfiguration'
         tags: 'Tags'
         internal_settings: 'Interne Einstellungen'
@@ -194,6 +195,7 @@ entry:
         starred: 'Favorisierte Einträge'
         archived: 'Archivierte Einträge'
         filtered: 'Gefilterte Einträge'
+        # with_annotations: 'Entries with annotations'
         filtered_tags: 'Gefiltert nach Tags:'
         filtered_search: 'Gefiltert nach Suche:'
         untagged: 'Nicht getaggte Einträge'
index 1bc32423aeb572e01cc3c8954444ba8aa2053a64..6e7f5693485ce76c218d7f9d66faec3ee8271511 100644 (file)
@@ -20,6 +20,7 @@ menu:
         starred: 'Starred'
         archive: 'Archive'
         all_articles: 'All entries'
+        with_annotations: 'With annotations'
         config: 'Config'
         tags: 'Tags'
         internal_settings: 'Internal Settings'
@@ -194,6 +195,7 @@ entry:
         starred: 'Starred entries'
         archived: 'Archived entries'
         filtered: 'Filtered entries'
+        with_annotations: 'Entries with annotations'
         filtered_tags: 'Filtered by tags:'
         filtered_search: 'Filtered by search:'
         untagged: 'Untagged entries'
index bced72e95ac86666c279929a1fa938786e559c52..2164a6184140c26769096a0a5a9f4c5a34aebe51 100644 (file)
@@ -20,6 +20,7 @@ menu:
         starred: 'Favoritos'
         archive: 'Archivo'
         all_articles: 'Todos los artículos'
+        # with_annotations: 'With annotations'
         config: 'Configuración'
         tags: 'Etiquetas'
         internal_settings: 'Configuración interna'
@@ -194,6 +195,7 @@ entry:
         starred: 'Artículos favoritos'
         archived: 'Artículos archivados'
         filtered: 'Artículos filtrados'
+        # with_annotations: 'Entries with annotations'
         filtered_tags: 'Filtrado por etiquetas:'
         filtered_search: 'Filtrado por búsqueda:'
         untagged: 'Artículos sin etiquetas'
index 0704204aa10e2d99bfe57092a8ee7226abc92216..be14f53dd594b4910a8abe5a0b992e744063f56a 100644 (file)
@@ -20,6 +20,7 @@ menu:
         starred: 'برگزیده'
         archive: 'بایگانی'
         all_articles: 'همه'
+        # with_annotations: 'With annotations'
         config: 'پیکربندی'
         tags: 'برچسب‌ها'
         internal_settings: 'تنظیمات درونی'
@@ -194,6 +195,7 @@ entry:
         starred: 'مقاله‌های برگزیده'
         archived: 'مقاله‌های بایگانی‌شده'
         filtered: 'مقاله‌های فیلترشده'
+        # with_annotations: 'Entries with annotations'
         # filtered_tags: 'Filtered by tags:'
         # filtered_search: 'Filtered by search:'
         # untagged: 'Untagged entries'
index 5d5878eba15f52b299825f2159472bba2274c11a..65a87710b4a477938d8309ab49851ba054ecf4a0 100644 (file)
@@ -20,6 +20,7 @@ menu:
         starred: "Favoris"
         archive: "Lus"
         all_articles: "Tous les articles"
+        with_annotations: 'Avec annotations'
         config: "Configuration"
         tags: "Tags"
         internal_settings: "Configuration interne"
@@ -194,6 +195,7 @@ entry:
         starred: "Articles favoris"
         archived: "Articles lus"
         filtered: "Articles filtrés"
+        with_annotations: 'Articles avec annotations'
         filtered_tags: "Articles filtrés par tags :"
         filtered_search: "Articles filtrés par recherche :"
         untagged: "Article sans tag"
index 23e72f20a7574aad4569c9a4ee5bcb664862e618..ef1f0d9fa14c80db4cf5b38ade6c04f9133b73bb 100644 (file)
@@ -20,6 +20,7 @@ menu:
         starred: 'Preferiti'
         archive: 'Archivio'
         all_articles: 'Tutti'
+        # with_annotations: 'With annotations'
         config: 'Configurazione'
         tags: 'Etichette'
         internal_settings: 'Strumenti'
@@ -194,6 +195,7 @@ entry:
         starred: 'Contenuti preferiti'
         archived: 'Contenuti archiviati'
         filtered: 'Contenuti filtrati'
+        # with_annotations: 'Entries with annotations'
         filtered_tags: 'Filtrati per etichetta:'
         filtered_search: 'Filtrati per ricerca:'
         untagged: 'Articoli non etichettati'
index f6530a83083b5a62f95cea5278f03d426eaf36cb..d1a2d055eb7904ebe8d0aa546c6150dab23ae202 100644 (file)
@@ -20,6 +20,7 @@ menu:
         starred: 'お気に入り'
         archive: 'アーカイブ済み'
         all_articles: '全ての記事'
+        # with_annotations: 'With annotations'
         config: '設定'
         tags: 'タグ'
         internal_settings: '内部設定'
@@ -194,6 +195,7 @@ entry:
         starred: 'お気に入りの記事'
         archived: 'アーカイブ済みの記事'
         filtered: '記事の絞り込み'
+        # with_annotations: 'Entries with annotations'
         filtered_tags: 'タグ検索:'
         filtered_search: '単語検索:'
         untagged: 'タグの無い記事'
index 6ddff6ea75ee414d0786269d8d709f335de4253d..f4409dddafbb4f07ee03bcd67b299d0db24f9e57 100644 (file)
@@ -20,6 +20,7 @@ menu:
         starred: 'Favorits'
         archive: 'Legits'
         all_articles: 'Totes los articles'
+        # with_annotations: 'With annotations'
         config: 'Configuracion'
         tags: 'Etiquetas'
         internal_settings: 'Configuracion intèrna'
@@ -194,6 +195,7 @@ entry:
         starred: 'Articles favorits'
         archived: 'Articles legits'
         filtered: 'Articles filtrats'
+        # with_annotations: 'Entries with annotations'
         filtered_tags: 'Articles filtrats per etiquetas :'
         filtered_search: 'Articles filtrats per recèrca :'
         untagged: 'Articles sens etiqueta'
index 770477c96dcd142dbeaab1c1e58bc4a15943544e..d595796f723f8b11d9c8f280b12aca3c4744c764 100644 (file)
@@ -20,6 +20,7 @@ menu:
         starred: 'Oznaczone gwiazdką'
         archive: 'Archiwum'
         all_articles: 'Wszystkie'
+        # with_annotations: 'With annotations'
         config: 'Konfiguracja'
         tags: 'Tagi'
         internal_settings: 'Wewnętrzne ustawienia'
@@ -194,6 +195,7 @@ entry:
         starred: 'Wpisy oznaczone gwiazdką'
         archived: 'Zarchiwizowane wpisy'
         filtered: 'Odfiltrowane wpisy'
+        # with_annotations: 'Entries with annotations'
         filtered_tags: 'Filtrowane po tagach:'
         filtered_search: 'Filtrowanie po wyszukiwaniu:'
         untagged: 'Odtaguj wpisy'
index d993cb059a9b87093519a5fec262c491d13ffbd0..dcd0b89b137ef0620674aa4ec72ab0c8cb934dc0 100644 (file)
@@ -20,6 +20,7 @@ menu:
         starred: 'Destacado'
         archive: 'Arquivo'
         all_articles: 'Todos os artigos'
+        # with_annotations: 'With annotations'
         config: 'Configurações'
         tags: 'Tags'
         internal_settings: 'Configurações Internas'
@@ -194,6 +195,7 @@ entry:
         starred: 'Artigos destacados'
         archived: 'Artigos arquivados'
         filtered: 'Artigos filtrados'
+        # with_annotations: 'Entries with annotations'
         filtered_tags: 'Filtrar por tags:'
         filtered_search: 'Filtrar por busca:'
         untagged: 'Entradas sem tags'
index bc8b72e0b15523a32d8ce51cad4368c48b0f35c9..d699a7493fdf1ae197ef1ff710e1164234f89c8f 100644 (file)
@@ -20,6 +20,7 @@ menu:
         starred: 'Cu steluță'
         archive: 'Arhivă'
         all_articles: 'Toate'
+        # with_annotations: 'With annotations'
         config: 'Configurație'
         tags: 'Tag-uri'
         # internal_settings: 'Internal Settings'
@@ -194,6 +195,7 @@ entry:
         # starred: 'Starred entries'
         # archived: 'Archived entries'
         # filtered: 'Filtered entries'
+        # with_annotations: 'Entries with annotations'
         # filtered_tags: 'Filtered by tags:'
         # filtered_search: 'Filtered by search:'
         # untagged: 'Untagged entries'
index 2f7f55e535f319da6b88999cda83f90bc4b1cf2f..13a257efc2067d2cedd3c2b5ce1dd3da1b770b97 100644 (file)
@@ -20,6 +20,7 @@ menu:
         starred: 'Помеченные'
         archive: 'Архивные'
         all_articles: 'Все записи'
+        # with_annotations: 'With annotations'
         config: 'Настройки'
         tags: 'Теги'
         internal_settings: 'Внутренние настройки'
@@ -194,6 +195,7 @@ entry:
         starred: 'Помеченные записи'
         archived: 'Архивные записи'
         filtered: 'Отфильтрованные записи'
+        # with_annotations: 'Entries with annotations'
         filtered_tags: 'Отфильтрованные по тегу:'
         filtered_search: 'Отфильтрованные по поиску:'
         untagged: 'Записи без тегов'
index 48e1c34ad13aafe67f494cc2e604ea32ff2c73e2..495f9337feb70767edc6abdac0ceefba6f457fcc 100644 (file)
@@ -20,6 +20,7 @@ menu:
         starred: 'ทำการแสดง'
         archive: 'เอกสาร'
         all_articles: 'รายการทั้งหมด'
+        # with_annotations: 'With annotations'
         config: 'กำหนดค่า'
         tags: 'แท็ก'
         internal_settings: 'ตั้งค่าภายใน'
@@ -194,6 +195,7 @@ entry:
         starred: 'รายการที่แสดง'
         archived: 'รายการเอกสาร'
         filtered: 'รายการที่กลั่นกรอง'
+        # with_annotations: 'Entries with annotations'
         filtered_tags: 'แท็กทีกลั่นกรอง่:'
         filtered_search: 'การค้นหาที่กลั่นกรอง:'
         untagged: 'รายการที่ไม่ได้แท็ก'
index 19029c0b1cabcd262db74f090dac40bf947fbcb3..163dc1d1f703dfea687ad8567f5ec00da6dd10f1 100644 (file)
@@ -20,6 +20,7 @@ menu:
         starred: 'Favoriler'
         archive: 'Arşiv'
         all_articles: 'Hepsi'
+        # with_annotations: 'With annotations'
         config: 'Yapılandırma'
         tags: 'Etiketler'
         # internal_settings: 'Internal Settings'
@@ -194,6 +195,7 @@ entry:
         # starred: 'Starred entries'
         # archived: 'Archived entries'
         # filtered: 'Filtered entries'
+        # with_annotations: 'Entries with annotations'
         # filtered_tags: 'Filtered by tags:'
         # filtered_search: 'Filtered by search:'
         # untagged: 'Untagged entries'
index f48ce37a89ae69dfdebbeca1841a6cfb560d2149..115701da21444351d9622ac4f571e96dea87d838 100644 (file)
@@ -20,6 +20,7 @@ menu:
         starred: '星标'
         archive: '存档'
         all_articles: '所有项目'
+        # with_annotations: 'With annotations'
         config: '配置'
         tags: '标签'
         internal_settings: '内部设置'
@@ -194,6 +195,7 @@ entry:
         starred: '星标项目'
         archived: '存档项目'
         filtered: '筛选后项目'
+        # with_annotations: 'Entries with annotations'
         filtered_tags: '根据标签筛选:'
         filtered_search: '根据搜索筛选:'
         untagged: '无标签项目'
index 5c17e9f7b78d5ced3f91807059e0c8f2b466b224..d93e5a674077230fdea0a99dc0ecb67d1c8b359b 100644 (file)
@@ -12,6 +12,8 @@
     {{ 'entry.page_titles.filtered_tags'|trans }} {{ filter }}
 {% elseif currentRoute == 'untagged' %}
     {{ 'entry.page_titles.untagged'|trans }}
+{% elseif currentRoute == 'with_annotations' %}
+    {{ 'entry.page_titles.with_annotations'|trans }}
 {% else %}
     {{ 'entry.page_titles.unread'|trans }}
 {% endif %}
index c51d07fc2a64f8e121f34a0b05f743eb9b5f54a3..6c4ae40b34d4424aa786a291591725f3dc98a8e0 100644 (file)
@@ -40,6 +40,8 @@
             {% set activeRoute = null %}
             {% if currentRoute == 'all' or currentRouteFromQueryParams == 'all' %}
                {% set activeRoute = 'all' %}
+            {% elseif currentRoute == 'with_annotations' or currentRouteFromQueryParams == 'with_annotations' %}
+               {% set activeRoute = 'with_annotations' %}
             {% elseif currentRoute == 'archive' or currentRouteFromQueryParams == 'archive' %}
                {% set activeRoute = 'archive' %}
             {% elseif currentRoute == 'starred' or currentRouteFromQueryParams == 'starred' %}
@@ -59,6 +61,9 @@
             <li class="bold {% if activeRoute == 'archive' %}active{% endif %}">
                 <a class="waves-effect" href="{{ path('archive') }}">{{ 'menu.left.archive'|trans }} <span class="numberItems grey-text">{{ count_entries('archive') }}</span></a>
             </li>
+            <li class="bold {% if activeRoute == 'with_annotations' %}active{% endif %}">
+                <a class="waves-effect" href="{{ path('with_annotations') }}">{{ 'menu.left.with_annotations'|trans }} <span class="numberItems grey-text">{{ count_entries('with_annotations') }}</span></a>
+            </li>
             <li class="bold {% if activeRoute == 'all' %}active{% endif %}">
                 <a class="waves-effect" href="{{ path('all') }}">{{ 'menu.left.all_articles'|trans }} <span class="numberItems grey-text">{{ count_entries('all') }}</span></a>
             </li>
index 47af3c8ec69afb6028bd5b08f05a488b5af5c2a5..e0f67375fb14da7c84678eeaa161683ed01dd334 100644 (file)
@@ -94,6 +94,9 @@ class WallabagExtension extends AbstractExtension implements GlobalsInterface
             case 'unread':
                 $qb = $this->entryRepository->getBuilderForUnreadByUser($user->getId());
                 break;
+            case 'with_annotations':
+                $qb = $this->entryRepository->getBuilderForAnnotationsByUser($user->getId());
+                break;
             case 'all':
                 $qb = $this->entryRepository->getBuilderForAllByUser($user->getId());
                 break;