mirror of
https://github.com/wallabag/wallabag.git
synced 2025-02-16 18:55:15 +00:00
Merge branch '2.6' into port/2.6.4-2.6.6
Signed-off-by: Kevin Decherf <kevin@kdecherf.com>
This commit is contained in:
commit
2910fb6da4
17 changed files with 234 additions and 49 deletions
2
.github/workflows/assets.yml
vendored
2
.github/workflows/assets.yml
vendored
|
@ -5,7 +5,7 @@ on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- 2.*
|
- "2.**"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
2
.github/workflows/coding-standards.yml
vendored
2
.github/workflows/coding-standards.yml
vendored
|
@ -5,7 +5,7 @@ on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- 2.*
|
- "2.**"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
2
.github/workflows/continuous-integration.yml
vendored
2
.github/workflows/continuous-integration.yml
vendored
|
@ -5,7 +5,7 @@ on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- 2.*
|
- "2.**"
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PGPASSWORD: wallabagrocks
|
PGPASSWORD: wallabagrocks
|
||||||
|
|
2
.github/workflows/translations.yml
vendored
2
.github/workflows/translations.yml
vendored
|
@ -5,7 +5,7 @@ on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- 2.*
|
- "2.**"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
27
CHANGELOG.md
27
CHANGELOG.md
|
@ -1,5 +1,32 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [2.6.6](https://github.com/wallabag/wallabag/tree/2.6.6)
|
||||||
|
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.5...2.6.6)
|
||||||
|
|
||||||
|
### Security fix
|
||||||
|
* Force secure cookie on HTTPS connection by @j0k3r in https://github.com/wallabag/wallabag/pull/6924
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fix checkboxes pointer events issue by @Simounet in https://github.com/wallabag/wallabag/pull/6897
|
||||||
|
* Add Google mailer by @j0k3r in https://github.com/wallabag/wallabag/pull/6899
|
||||||
|
* Improve performance on homepage by @Simounet in https://github.com/wallabag/wallabag/pull/6909
|
||||||
|
* Mass action layout improved by @Simounet in https://github.com/wallabag/wallabag/pull/6912
|
||||||
|
|
||||||
|
## [2.6.5](https://github.com/wallabag/wallabag/tree/2.6.5)
|
||||||
|
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.4...2.6.5)
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* "Fix checkboxes pointer-events disabled" by @Simounet https://github.com/wallabag/wallabag/pull/6874
|
||||||
|
* "Fix nav input styles" by @Simounet https://github.com/wallabag/wallabag/pull/6877
|
||||||
|
* "Change domain status filters html types" by @Simounet https://github.com/wallabag/wallabag/pull/6888
|
||||||
|
|
||||||
|
## [2.6.4](https://github.com/wallabag/wallabag/tree/2.6.4)
|
||||||
|
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.3...2.6.4)
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
* Fix API token generation by @nicosomb https://github.com/wallabag/wallabag/pull/6869
|
||||||
|
* Fix checkboxes which were broken by @nicosomb https://github.com/wallabag/wallabag/pull/6864
|
||||||
|
|
||||||
## [2.6.3](https://github.com/wallabag/wallabag/tree/2.6.3)
|
## [2.6.3](https://github.com/wallabag/wallabag/tree/2.6.3)
|
||||||
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.2...2.6.3)
|
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.2...2.6.3)
|
||||||
|
|
||||||
|
|
|
@ -14,25 +14,30 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.mass-action {
|
.mass-action {
|
||||||
margin: 10px 5px 10px 20px;
|
margin: 20px 5px 10px 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mass-action-group {
|
.mass-action-group {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
gap: 10px;
|
align-items: center;
|
||||||
|
gap: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mass-action-button {
|
.mass-action-button {
|
||||||
height: 24px;
|
height: 36px;
|
||||||
line-height: 24px;
|
line-height: 36px;
|
||||||
padding: 0 0.5rem;
|
padding: 0 0.7rem;
|
||||||
|
|
||||||
i {
|
i {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mass-action-button--tags {
|
||||||
|
border-radius: 2px 0 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
.entry-checkbox {
|
.entry-checkbox {
|
||||||
margin: 10px 15px 10px 5px;
|
margin: 10px 15px 10px 5px;
|
||||||
|
|
||||||
|
@ -64,11 +69,19 @@
|
||||||
|
|
||||||
.mass-action-tags {
|
.mass-action-tags {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
margin-top: 10px;
|
||||||
gap: 10px;
|
|
||||||
|
|
||||||
.mass-action-tags-input {
|
.mass-action-tags-input.mass-action-tags-input {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
padding: 0 5px;
|
||||||
|
height: 34px;
|
||||||
|
background: white;
|
||||||
|
border-bottom: 3px solid #c5ebef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mass-action-tags-input.mass-action-tags-input.mass-action-tags-input:focus {
|
||||||
|
border-bottom: 3px solid $blue-accent-color;
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,13 +101,16 @@
|
||||||
|
|
||||||
.results {
|
.results {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
margin-bottom: 10px;
|
||||||
padding: 1rem 1rem 0;
|
padding: 1rem 1rem 0;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
.nb-results {
|
.nb-results {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
}
|
margin-bottom: 20px;
|
||||||
|
gap: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.results-item {
|
.results-item {
|
||||||
|
@ -173,9 +189,38 @@ footer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 993px) {
|
@media screen and (min-width: 993px) {
|
||||||
|
.results {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nb-results {
|
||||||
|
margin-bottom: 0;
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mass-action-button {
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mass-action-group {
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mass-action-tags {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-left: 7px;
|
||||||
|
flex-wrap: initial;
|
||||||
|
}
|
||||||
|
|
||||||
.mass-action {
|
.mass-action {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
margin-top: 10px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 30px;
|
|
||||||
|
.mass-action-tags-input.mass-action-tags-input {
|
||||||
|
height: 21px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,7 @@ nav {
|
||||||
|
|
||||||
.input-field input {
|
.input-field input {
|
||||||
display: block;
|
display: block;
|
||||||
|
font-size: 1.2rem;
|
||||||
line-height: inherit;
|
line-height: inherit;
|
||||||
height: 3rem;
|
height: 3rem;
|
||||||
}
|
}
|
||||||
|
@ -79,6 +80,17 @@ nav {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
color: #444;
|
color: #444;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* materializecss override */
|
||||||
|
.input-field.input-field input {
|
||||||
|
margin-bottom: 0;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-field.input-field input:focus {
|
||||||
|
border-bottom: none;
|
||||||
|
box-shadow: initial;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-panel-top {
|
.nav-panel-top {
|
||||||
|
|
|
@ -15,6 +15,13 @@ div.settings div.file-field {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* override materializecss pointer-event disabled on checkboxes */
|
||||||
|
[type="checkbox"]:not(:checked),
|
||||||
|
[type="checkbox"]:checked,
|
||||||
|
.input-field label {
|
||||||
|
pointer-events: initial;
|
||||||
|
}
|
||||||
|
|
||||||
.input-field label.active {
|
.input-field label.active {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ framework:
|
||||||
# handler_id set to null will use default session handler from php.ini
|
# handler_id set to null will use default session handler from php.ini
|
||||||
handler_id: session.handler.native_file
|
handler_id: session.handler.native_file
|
||||||
save_path: "%kernel.project_dir%/var/sessions/%kernel.environment%"
|
save_path: "%kernel.project_dir%/var/sessions/%kernel.environment%"
|
||||||
|
cookie_secure: auto
|
||||||
fragments: ~
|
fragments: ~
|
||||||
http_method_override: true
|
http_method_override: true
|
||||||
assets: ~
|
assets: ~
|
||||||
|
@ -84,13 +85,8 @@ doctrine_migrations:
|
||||||
executed_at_column_name: 'executed_at'
|
executed_at_column_name: 'executed_at'
|
||||||
|
|
||||||
fos_rest:
|
fos_rest:
|
||||||
zone:
|
|
||||||
- { path: ^/api }
|
|
||||||
- { path: ^/annotations }
|
|
||||||
param_fetcher_listener: true
|
param_fetcher_listener: true
|
||||||
body_listener: true
|
body_listener: true
|
||||||
exception:
|
|
||||||
serializer_error_renderer: true
|
|
||||||
view:
|
view:
|
||||||
mime_types:
|
mime_types:
|
||||||
csv:
|
csv:
|
||||||
|
@ -116,6 +112,9 @@ fos_rest:
|
||||||
- { path: "^/api/entries/([0-9]+)/export.(.*)", priorities: ['epub', 'pdf', 'txt', 'csv'], fallback_format: json, prefer_extension: false }
|
- { path: "^/api/entries/([0-9]+)/export.(.*)", priorities: ['epub', 'pdf', 'txt', 'csv'], fallback_format: json, prefer_extension: false }
|
||||||
- { path: "^/api", priorities: ['json', 'xml'], fallback_format: json, prefer_extension: false }
|
- { path: "^/api", priorities: ['json', 'xml'], fallback_format: json, prefer_extension: false }
|
||||||
- { path: "^/annotations", priorities: ['json', 'xml'], fallback_format: json, prefer_extension: false }
|
- { path: "^/annotations", priorities: ['json', 'xml'], fallback_format: json, prefer_extension: false }
|
||||||
|
# for an unknown reason, EACH REQUEST goes to FOS\RestBundle\EventListener\FormatListener
|
||||||
|
# so we need to add custom rule for custom api export but also for all other routes of the application...
|
||||||
|
- { path: '^/', priorities: ['text/html', '*/*'], fallback_format: html, prefer_extension: false }
|
||||||
|
|
||||||
nelmio_api_doc:
|
nelmio_api_doc:
|
||||||
areas:
|
areas:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
wallabag_core:
|
wallabag_core:
|
||||||
version: 2.6.3
|
version: 2.6.6
|
||||||
paypal_url: "https://liberapay.com/wallabag/donate"
|
paypal_url: "https://liberapay.com/wallabag/donate"
|
||||||
languages:
|
languages:
|
||||||
en: 'English'
|
en: 'English'
|
||||||
|
|
|
@ -130,6 +130,7 @@
|
||||||
"symfony/finder": "^4.4",
|
"symfony/finder": "^4.4",
|
||||||
"symfony/form": "^4.4",
|
"symfony/form": "^4.4",
|
||||||
"symfony/framework-bundle": "^4.4",
|
"symfony/framework-bundle": "^4.4",
|
||||||
|
"symfony/google-mailer": "^4.4",
|
||||||
"symfony/http-foundation": "^4.4",
|
"symfony/http-foundation": "^4.4",
|
||||||
"symfony/http-kernel": "^4.4",
|
"symfony/http-kernel": "^4.4",
|
||||||
"symfony/mailer": "^4.4",
|
"symfony/mailer": "^4.4",
|
||||||
|
@ -209,7 +210,11 @@
|
||||||
"incenteev-parameters": {
|
"incenteev-parameters": {
|
||||||
"file": "app/config/parameters.yml"
|
"file": "app/config/parameters.yml"
|
||||||
},
|
},
|
||||||
"public-dir": "web"
|
"public-dir": "web",
|
||||||
|
"symfony": {
|
||||||
|
"allow-contrib": true,
|
||||||
|
"require": "4.4.*"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"post-install-cmd": [
|
"post-install-cmd": [
|
||||||
|
|
|
@ -675,9 +675,6 @@ class EntryController extends AbstractController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$nbEntriesUntagged = $this->entryRepository
|
|
||||||
->countUntaggedEntriesByUser($this->getUser()->getId());
|
|
||||||
|
|
||||||
return $this->render(
|
return $this->render(
|
||||||
'@WallabagCore/Entry/entries.html.twig', [
|
'@WallabagCore/Entry/entries.html.twig', [
|
||||||
'form' => $form->createView(),
|
'form' => $form->createView(),
|
||||||
|
@ -685,7 +682,6 @@ class EntryController extends AbstractController
|
||||||
'currentPage' => $page,
|
'currentPage' => $page,
|
||||||
'searchTerm' => $searchTerm,
|
'searchTerm' => $searchTerm,
|
||||||
'isFiltered' => $form->isSubmitted(),
|
'isFiltered' => $form->isSubmitted(),
|
||||||
'nbEntriesUntagged' => $nbEntriesUntagged,
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ use Lexik\Bundle\FormFilterBundle\Filter\FilterOperands;
|
||||||
use Lexik\Bundle\FormFilterBundle\Filter\Form\Type\CheckboxFilterType;
|
use Lexik\Bundle\FormFilterBundle\Filter\Form\Type\CheckboxFilterType;
|
||||||
use Lexik\Bundle\FormFilterBundle\Filter\Form\Type\ChoiceFilterType;
|
use Lexik\Bundle\FormFilterBundle\Filter\Form\Type\ChoiceFilterType;
|
||||||
use Lexik\Bundle\FormFilterBundle\Filter\Form\Type\DateRangeFilterType;
|
use Lexik\Bundle\FormFilterBundle\Filter\Form\Type\DateRangeFilterType;
|
||||||
|
use Lexik\Bundle\FormFilterBundle\Filter\Form\Type\NumberFilterType;
|
||||||
use Lexik\Bundle\FormFilterBundle\Filter\Form\Type\NumberRangeFilterType;
|
use Lexik\Bundle\FormFilterBundle\Filter\Form\Type\NumberRangeFilterType;
|
||||||
use Lexik\Bundle\FormFilterBundle\Filter\Form\Type\TextFilterType;
|
use Lexik\Bundle\FormFilterBundle\Filter\Form\Type\TextFilterType;
|
||||||
use Lexik\Bundle\FormFilterBundle\Filter\Query\QueryInterface;
|
use Lexik\Bundle\FormFilterBundle\Filter\Query\QueryInterface;
|
||||||
|
@ -102,10 +103,13 @@ class EntryFilterType extends AbstractType
|
||||||
return $filterQuery->createCondition($expression);
|
return $filterQuery->createCondition($expression);
|
||||||
},
|
},
|
||||||
'label' => 'entry.filters.domain_label',
|
'label' => 'entry.filters.domain_label',
|
||||||
|
'attr' => [
|
||||||
|
'autocapitalize' => 'off',
|
||||||
|
],
|
||||||
])
|
])
|
||||||
->add('httpStatus', TextFilterType::class, [
|
->add('httpStatus', NumberFilterType::class, [
|
||||||
'apply_filter' => function (QueryInterface $filterQuery, $field, $values) {
|
'apply_filter' => function (QueryInterface $filterQuery, $field, $values) {
|
||||||
$value = $values['value'];
|
$value = (int) $values['value'];
|
||||||
if (false === \array_key_exists($value, Response::$statusTexts)) {
|
if (false === \array_key_exists($value, Response::$statusTexts)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -117,6 +121,11 @@ class EntryFilterType extends AbstractType
|
||||||
return $filterQuery->createCondition($expression, $parameters);
|
return $filterQuery->createCondition($expression, $parameters);
|
||||||
},
|
},
|
||||||
'label' => 'entry.filters.http_status_label',
|
'label' => 'entry.filters.http_status_label',
|
||||||
|
'html5' => true,
|
||||||
|
'attr' => [
|
||||||
|
'min' => 100,
|
||||||
|
'max' => 527,
|
||||||
|
],
|
||||||
])
|
])
|
||||||
->add('isArchived', CheckboxFilterType::class, [
|
->add('isArchived', CheckboxFilterType::class, [
|
||||||
'label' => 'entry.filters.archived_label',
|
'label' => 'entry.filters.archived_label',
|
||||||
|
|
|
@ -37,6 +37,20 @@ class EntryRepository extends ServiceEntityRepository
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves all entries count for a user.
|
||||||
|
*
|
||||||
|
* @param int $userId
|
||||||
|
*
|
||||||
|
* @return QueryBuilder
|
||||||
|
*/
|
||||||
|
public function getCountBuilderForAllByUser($userId)
|
||||||
|
{
|
||||||
|
return $this
|
||||||
|
->getQueryBuilderByUser($userId)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves unread entries for a user.
|
* Retrieves unread entries for a user.
|
||||||
*
|
*
|
||||||
|
@ -52,6 +66,21 @@ class EntryRepository extends ServiceEntityRepository
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves unread entries count for a user.
|
||||||
|
*
|
||||||
|
* @param int $userId
|
||||||
|
*
|
||||||
|
* @return QueryBuilder
|
||||||
|
*/
|
||||||
|
public function getCountBuilderForUnreadByUser($userId)
|
||||||
|
{
|
||||||
|
return $this
|
||||||
|
->getQueryBuilderByUser($userId)
|
||||||
|
->andWhere('e.isArchived = false')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves entries with the same domain.
|
* Retrieves entries with the same domain.
|
||||||
*
|
*
|
||||||
|
@ -94,6 +123,21 @@ class EntryRepository extends ServiceEntityRepository
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves read entries count for a user.
|
||||||
|
*
|
||||||
|
* @param int $userId
|
||||||
|
*
|
||||||
|
* @return QueryBuilder
|
||||||
|
*/
|
||||||
|
public function getCountBuilderForArchiveByUser($userId)
|
||||||
|
{
|
||||||
|
return $this
|
||||||
|
->getQueryBuilderByUser($userId)
|
||||||
|
->andWhere('e.isArchived = true')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves starred entries for a user.
|
* Retrieves starred entries for a user.
|
||||||
*
|
*
|
||||||
|
@ -109,6 +153,21 @@ class EntryRepository extends ServiceEntityRepository
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves starred entries count for a user.
|
||||||
|
*
|
||||||
|
* @param int $userId
|
||||||
|
*
|
||||||
|
* @return QueryBuilder
|
||||||
|
*/
|
||||||
|
public function getCountBuilderForStarredByUser($userId)
|
||||||
|
{
|
||||||
|
return $this
|
||||||
|
->getQueryBuilderByUser($userId)
|
||||||
|
->andWhere('e.isStarred = true')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves entries filtered with a search term for a user.
|
* Retrieves entries filtered with a search term for a user.
|
||||||
*
|
*
|
||||||
|
@ -169,6 +228,21 @@ class EntryRepository extends ServiceEntityRepository
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve entries with annotations count for a user.
|
||||||
|
*
|
||||||
|
* @param int $userId
|
||||||
|
*
|
||||||
|
* @return QueryBuilder
|
||||||
|
*/
|
||||||
|
public function getCountBuilderForAnnotationsByUser($userId)
|
||||||
|
{
|
||||||
|
return $this
|
||||||
|
->getQueryBuilderByUser($userId)
|
||||||
|
->innerJoin('e.annotations', 'a')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve untagged entries for a user.
|
* Retrieve untagged entries for a user.
|
||||||
*
|
*
|
||||||
|
@ -588,6 +662,23 @@ class EntryRepository extends ServiceEntityRepository
|
||||||
return $qb->getQuery()->getArrayResult();
|
return $qb->getQuery()->getArrayResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $userId
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function findEmptyEntriesIdByUserId($userId = null)
|
||||||
|
{
|
||||||
|
$qb = $this->createQueryBuilder('e')
|
||||||
|
->select('e.id');
|
||||||
|
|
||||||
|
if (null !== $userId) {
|
||||||
|
$qb->where('e.user = :userid AND e.content IS NULL')->setParameter(':userid', $userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $qb->getQuery()->getArrayResult();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find all entries by url and owner.
|
* Find all entries by url and owner.
|
||||||
*
|
*
|
||||||
|
|
|
@ -53,13 +53,11 @@
|
||||||
<button class="mass-action-button btn cyan darken-1" type="submit" name="toggle-read" title="{{ 'entry.list.toogle_as_read'|trans }}"><i class="material-icons">done</i></button>
|
<button class="mass-action-button btn cyan darken-1" type="submit" name="toggle-read" title="{{ 'entry.list.toogle_as_read'|trans }}"><i class="material-icons">done</i></button>
|
||||||
<button class="mass-action-button btn cyan darken-1" type="submit" name="toggle-star" title="{{ 'entry.list.toogle_as_star'|trans }}" ><i class="material-icons">star</i></button>
|
<button class="mass-action-button btn cyan darken-1" type="submit" name="toggle-star" title="{{ 'entry.list.toogle_as_star'|trans }}" ><i class="material-icons">star</i></button>
|
||||||
<button class="mass-action-button btn cyan darken-1" type="submit" name="delete" onclick="return confirm('{{ 'entry.confirm.delete_entries'|trans|escape('js') }}')" title="{{ 'entry.list.delete'|trans }}"><i class="material-icons">delete</i></button>
|
<button class="mass-action-button btn cyan darken-1" type="submit" name="delete" onclick="return confirm('{{ 'entry.confirm.delete_entries'|trans|escape('js') }}')" title="{{ 'entry.list.delete'|trans }}"><i class="material-icons">delete</i></button>
|
||||||
<label for="mass-action-tags-displayed" class="mass-action-button btn cyan darken-1" type="button" title="{{ 'entry.list.add_tags'|trans }}"><i class="material-icons">label</i></label>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input id="mass-action-tags-displayed" class="toggle-checkbox" type="checkbox" />
|
|
||||||
<div class="mass-action-tags">
|
<div class="mass-action-tags">
|
||||||
|
<button class="btn cyan darken-1 mass-action-button mass-action-button--tags" type="submit" name="tag" title="{{ 'entry.list.add_tags'|trans }}"><i class="material-icons">label</i></button>
|
||||||
<input type="text" class="mass-action-tags-input" name="tags" placeholder="{{ 'entry.list.mass_action_tags_input_placeholder'|trans }}" />
|
<input type="text" class="mass-action-tags-input" name="tags" placeholder="{{ 'entry.list.mass_action_tags_input_placeholder'|trans }}" />
|
||||||
<button class="btn cyan darken-1" type="submit" name="tag">{{ 'entry.list.add_tags'|trans }}</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -117,9 +115,9 @@
|
||||||
<h4 class="center">{{ 'entry.filters.title'|trans }}</h4>
|
<h4 class="center">{{ 'entry.filters.title'|trans }}</h4>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% if current_route != 'untagged' and nbEntriesUntagged != 0 %}
|
{% if current_route != 'untagged' %}
|
||||||
<div class="col s12 center-align">
|
<div class="col s12 center-align">
|
||||||
<a href="{{ path('untagged') }}">{{ 'tag.list.see_untagged_entries'|trans }} ({{ nbEntriesUntagged }})</a>
|
<a href="{{ path('untagged') }}">{{ 'tag.list.see_untagged_entries'|trans }}</a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
@ -168,7 +168,7 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col m12 l8">
|
<div class="col m12 l8">
|
||||||
<p class="footer-text" title="{{ display_stats()|raw|striptags }}">
|
<p class="footer-text">
|
||||||
{{ display_stats() }}
|
{{ display_stats() }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -96,35 +96,32 @@ class WallabagExtension extends AbstractExtension implements GlobalsInterface
|
||||||
|
|
||||||
switch ($type) {
|
switch ($type) {
|
||||||
case 'starred':
|
case 'starred':
|
||||||
$qb = $this->entryRepository->getBuilderForStarredByUser($user->getId());
|
$qb = $this->entryRepository->getCountBuilderForStarredByUser($user->getId());
|
||||||
break;
|
break;
|
||||||
case 'archive':
|
case 'archive':
|
||||||
$qb = $this->entryRepository->getBuilderForArchiveByUser($user->getId());
|
$qb = $this->entryRepository->getCountBuilderForArchiveByUser($user->getId());
|
||||||
break;
|
break;
|
||||||
case 'unread':
|
case 'unread':
|
||||||
$qb = $this->entryRepository->getBuilderForUnreadByUser($user->getId());
|
$qb = $this->entryRepository->getCountBuilderForUnreadByUser($user->getId());
|
||||||
break;
|
break;
|
||||||
case 'annotated':
|
case 'annotated':
|
||||||
$qb = $this->entryRepository->getBuilderForAnnotationsByUser($user->getId());
|
$qb = $this->entryRepository->getCountBuilderForAnnotationsByUser($user->getId());
|
||||||
break;
|
break;
|
||||||
case 'all':
|
case 'all':
|
||||||
$qb = $this->entryRepository->getBuilderForAllByUser($user->getId());
|
$qb = $this->entryRepository->getCountBuilderForAllByUser($user->getId());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new \InvalidArgumentException(sprintf('Type "%s" is not implemented.', $type));
|
throw new \InvalidArgumentException(sprintf('Type "%s" is not implemented.', $type));
|
||||||
}
|
}
|
||||||
|
|
||||||
// THANKS to PostgreSQL we CAN'T make a DEAD SIMPLE count(e.id)
|
|
||||||
// ERROR: column "e0_.id" must appear in the GROUP BY clause or be used in an aggregate function
|
|
||||||
$query = $qb
|
$query = $qb
|
||||||
->select('e.id')
|
->select('COUNT(e.id)')
|
||||||
->groupBy('e.id')
|
|
||||||
->getQuery();
|
->getQuery();
|
||||||
|
|
||||||
$query->useQueryCache(true);
|
$query->useQueryCache(true);
|
||||||
$query->enableResultCache($this->lifeTime);
|
$query->enableResultCache($this->lifeTime);
|
||||||
|
|
||||||
return \count($query->getArrayResult());
|
return $query->getSingleScalarResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -156,15 +153,14 @@ class WallabagExtension extends AbstractExtension implements GlobalsInterface
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = $this->entryRepository->getBuilderForArchiveByUser($user->getId())
|
$query = $this->entryRepository->getCountBuilderForArchiveByUser($user->getId())
|
||||||
->select('e.id')
|
->select('COUNT(e.id)')
|
||||||
->groupBy('e.id')
|
|
||||||
->getQuery();
|
->getQuery();
|
||||||
|
|
||||||
$query->useQueryCache(true);
|
$query->useQueryCache(true);
|
||||||
$query->enableResultCache($this->lifeTime);
|
$query->enableResultCache($this->lifeTime);
|
||||||
|
|
||||||
$nbArchives = \count($query->getArrayResult());
|
$nbArchives = $query->getSingleScalarResult();
|
||||||
|
|
||||||
$interval = $user->getCreatedAt()->diff(new \DateTime('now'));
|
$interval = $user->getCreatedAt()->diff(new \DateTime('now'));
|
||||||
$nbDays = (int) $interval->format('%a') ?: 1;
|
$nbDays = (int) $interval->format('%a') ?: 1;
|
||||||
|
|
Loading…
Reference in a new issue