Compare commits

..

56 Commits

Author SHA1 Message Date
5981cfb8b8 Support sorting by reading time and URL in filter view
Signed-off-by: Kevin Decherf <kevin@kdecherf.com>
2025-08-19 00:23:56 +02:00
7e8a3c432f Add sorting function to filter view
Fixes #2178

Signed-off-by: Kevin Decherf <kevin@kdecherf.com>
2025-08-19 00:22:47 +02:00
a97e84a21e Merge pull request #8425 from wallabag/dependabot/npm_and_yarn/babel-dependencies-7678d992f1
Bump the babel-dependencies group with 2 updates
2025-08-18 09:11:26 +00:00
0371188aa4 Merge pull request #8423 from wallabag/dependabot/github_actions/actions/checkout-5
Bump actions/checkout from 4 to 5
2025-08-18 09:59:38 +02:00
61b1bb9261 Merge pull request #8426 from wallabag/dependabot/npm_and_yarn/mini-css-extract-plugin-2.9.4
Bump mini-css-extract-plugin from 2.9.3 to 2.9.4
2025-08-18 04:14:48 +00:00
7e6de2117f Merge pull request #8424 from wallabag/dependabot/npm_and_yarn/webpack-5.101.2
Bump webpack from 5.101.0 to 5.101.2
2025-08-18 04:09:30 +00:00
7c563b967e Bump mini-css-extract-plugin from 2.9.3 to 2.9.4
Bumps [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin) from 2.9.3 to 2.9.4.
- [Release notes](https://github.com/webpack-contrib/mini-css-extract-plugin/releases)
- [Changelog](https://github.com/webpack-contrib/mini-css-extract-plugin/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/mini-css-extract-plugin/compare/v2.9.3...v2.9.4)

---
updated-dependencies:
- dependency-name: mini-css-extract-plugin
  dependency-version: 2.9.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 04:09:11 +00:00
4517cb3b0a Bump the babel-dependencies group with 2 updates
Bumps the babel-dependencies group with 2 updates: [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) and [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env).


Updates `@babel/core` from 7.28.0 to 7.28.3
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.28.3/packages/babel-core)

Updates `@babel/preset-env` from 7.28.0 to 7.28.3
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.28.3/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-version: 7.28.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: babel-dependencies
- dependency-name: "@babel/preset-env"
  dependency-version: 7.28.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: babel-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 04:09:02 +00:00
b1502333a6 Bump webpack from 5.101.0 to 5.101.2
Bumps [webpack](https://github.com/webpack/webpack) from 5.101.0 to 5.101.2.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.101.0...v5.101.2)

---
updated-dependencies:
- dependency-name: webpack
  dependency-version: 5.101.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 04:05:57 +00:00
69b6983df6 Bump actions/checkout from 4 to 5
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 03:25:09 +00:00
2ee88ffe4e Merge pull request #8409 from wallabag/dependabot/composer/enshrined/svg-sanitize-0.22.0
Bump enshrined/svg-sanitize from 0.21.0 to 0.22.0
2025-08-13 09:47:53 +02:00
96133123da Bump enshrined/svg-sanitize from 0.21.0 to 0.22.0
Bumps [enshrined/svg-sanitize](https://github.com/darylldoyle/svg-sanitizer) from 0.21.0 to 0.22.0.
- [Release notes](https://github.com/darylldoyle/svg-sanitizer/releases)
- [Commits](https://github.com/darylldoyle/svg-sanitizer/compare/0.21.0...0.22.0)

---
updated-dependencies:
- dependency-name: enshrined/svg-sanitize
  dependency-version: 0.22.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-13 04:43:26 +00:00
f6ca2b9ff8 Merge pull request #8407 from wallabag/dependabot/npm_and_yarn/sass-embedded-1.90.0
Bump sass-embedded from 1.89.2 to 1.90.0
2025-08-09 20:59:19 +00:00
6c77dd1d15 Merge pull request #8406 from wallabag/dependabot/npm_and_yarn/mini-css-extract-plugin-2.9.3
Bump mini-css-extract-plugin from 2.9.2 to 2.9.3
2025-08-09 20:58:58 +00:00
f906f62a3f Merge pull request #8403 from wallabag/dependabot/npm_and_yarn/core-js-3.45.0
Bump core-js from 3.44.0 to 3.45.0
2025-08-09 20:57:31 +00:00
6fa6ebc0a4 Bump sass-embedded from 1.89.2 to 1.90.0
Bumps [sass-embedded](https://github.com/sass/embedded-host-node) from 1.89.2 to 1.90.0.
- [Changelog](https://github.com/sass/embedded-host-node/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/embedded-host-node/compare/1.89.2...1.90.0)

---
updated-dependencies:
- dependency-name: sass-embedded
  dependency-version: 1.90.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-09 20:46:28 +00:00
b443e9388d Bump mini-css-extract-plugin from 2.9.2 to 2.9.3
Bumps [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin) from 2.9.2 to 2.9.3.
- [Release notes](https://github.com/webpack-contrib/mini-css-extract-plugin/releases)
- [Changelog](https://github.com/webpack-contrib/mini-css-extract-plugin/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/mini-css-extract-plugin/compare/v2.9.2...v2.9.3)

---
updated-dependencies:
- dependency-name: mini-css-extract-plugin
  dependency-version: 2.9.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-09 20:46:08 +00:00
925c08fa83 Bump core-js from 3.44.0 to 3.45.0
Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.44.0 to 3.45.0.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/commits/v3.45.0/packages/core-js)

---
updated-dependencies:
- dependency-name: core-js
  dependency-version: 3.45.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-09 20:45:34 +00:00
896e81b229 Merge pull request #8392 from wallabag/misc/codeowners
Add CODEOWNERS, fix deprecation
2025-08-09 22:43:39 +02:00
efaa129ef1 Merge pull request #8395 from wallabag/dependabot/npm_and_yarn/tmp-0.2.4
Bump tmp from 0.2.3 to 0.2.4
2025-08-06 17:11:30 +00:00
75f9e2a144 Bump tmp from 0.2.3 to 0.2.4
Bumps [tmp](https://github.com/raszi/node-tmp) from 0.2.3 to 0.2.4.
- [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md)
- [Commits](https://github.com/raszi/node-tmp/compare/v0.2.3...v0.2.4)

---
updated-dependencies:
- dependency-name: tmp
  dependency-version: 0.2.4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-06 17:07:57 +00:00
61a28a5ca2 Add CODEOWNERS, fix deprecation
References:
- https://github.com/wallabag/wallabag/pull/8388#issuecomment-3148942621
- https://github.blog/changelog/2025-04-29-dependabot-reviewers-configuration-option-being-replaced-by-code-owners/
- https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners

Signed-off-by: Kevin Decherf <kevin@kdecherf.com>
2025-08-05 18:25:02 +02:00
0be919c8fd Merge pull request #8388 from wallabag/dependabot/composer/j0k3r/graby-site-config-1.0.202
Bump j0k3r/graby-site-config from 1.0.201 to 1.0.202
2025-08-05 18:10:28 +02:00
c2ae69edbb Merge pull request #8391 from wallabag/dependabot/npm_and_yarn/webpack-5.101.0
Bump webpack from 5.100.2 to 5.101.0
2025-08-04 03:37:55 +00:00
8b6f1696f4 Bump webpack from 5.100.2 to 5.101.0
Bumps [webpack](https://github.com/webpack/webpack) from 5.100.2 to 5.101.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.100.2...v5.101.0)

---
updated-dependencies:
- dependency-name: webpack
  dependency-version: 5.101.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-04 03:34:25 +00:00
6f76578a51 Bump j0k3r/graby-site-config from 1.0.201 to 1.0.202
Bumps [j0k3r/graby-site-config](https://github.com/j0k3r/graby-site-config) from 1.0.201 to 1.0.202.
- [Release notes](https://github.com/j0k3r/graby-site-config/releases)
- [Changelog](https://github.com/j0k3r/graby-site-config/blob/master/dallasnews.com.txt)
- [Commits](https://github.com/j0k3r/graby-site-config/compare/1.0.201...1.0.202)

---
updated-dependencies:
- dependency-name: j0k3r/graby-site-config
  dependency-version: 1.0.202
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-04 02:28:19 +00:00
3ad06d69a5 Merge pull request #8142 from wallabag/fix/2fa-setup
Add a two-step setup of OTP
2025-07-28 23:09:51 +02:00
b09224cac1 Add a two-step setup of OTP
Before this change, 2FA with OTP was enabled before the user was able to
submit a code to validate the setup. Thus, this could lead to a
situation where the user is locked out of her account if there was an
issue setting up her application.

Now we rely on a new boolean property that is set to true only after the
user submits a valid code during the setup phase.

Fixes #4867

Signed-off-by: Kevin Decherf <kevin@kdecherf.com>
2025-07-28 22:58:43 +02:00
3f6c01103d Merge pull request #8376 from alexislefebvre/patch-1
doc: update link to CI to lead to the main branch
2025-07-22 17:25:08 +02:00
396221376d Merge pull request #8379 from wallabag/dependabot/composer/friendsofphp/php-cs-fixer-3.84.0
Bump friendsofphp/php-cs-fixer from 3.82.2 to 3.84.0
2025-07-21 09:41:44 +02:00
d5c316dcc4 Bump friendsofphp/php-cs-fixer from 3.82.2 to 3.84.0
---
updated-dependencies:
- dependency-name: friendsofphp/php-cs-fixer
  dependency-version: 3.84.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-21 03:04:34 +00:00
24e240ca03 Merge pull request #8378 from wallabag/dependabot/npm_and_yarn/webpack-5.100.2
Bump webpack from 5.100.1 to 5.100.2
2025-07-21 02:32:22 +00:00
96f15e0246 Bump webpack from 5.100.1 to 5.100.2
---
updated-dependencies:
- dependency-name: webpack
  dependency-version: 5.100.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-21 02:28:37 +00:00
10bd1ed3d3 doc: update link to CI to lead to the main branch 2025-07-20 14:57:32 +02:00
487643c5f6 Merge pull request #8374 from wallabag/fix-static-pages
Fix about and quickstart pages
2025-07-18 16:40:02 +02:00
ebc066ec62 Fix about and quickstart pages 2025-07-18 16:32:36 +02:00
5b2e36f4d7 Merge pull request #8368 from wallabag/dependabot/composer/friendsofphp/php-cs-fixer-3.82.2
Bump friendsofphp/php-cs-fixer from 3.80.0 to 3.82.2
2025-07-15 14:27:51 +02:00
faeb9c5049 Merge pull request #8367 from wallabag/dependabot/composer/sentry/sentry-symfony-5.3.0
Bump sentry/sentry-symfony from 5.2.0 to 5.3.0
2025-07-15 14:27:34 +02:00
1064b65ed0 Bump friendsofphp/php-cs-fixer from 3.80.0 to 3.82.2
Bumps [friendsofphp/php-cs-fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer) from 3.80.0 to 3.82.2.
- [Release notes](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/releases)
- [Changelog](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/compare/v3.80.0...v3.82.2)

---
updated-dependencies:
- dependency-name: friendsofphp/php-cs-fixer
  dependency-version: 3.82.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-14 03:04:11 +00:00
b4e22ef367 Bump sentry/sentry-symfony from 5.2.0 to 5.3.0
Bumps [sentry/sentry-symfony](https://github.com/getsentry/sentry-symfony) from 5.2.0 to 5.3.0.
- [Release notes](https://github.com/getsentry/sentry-symfony/releases)
- [Changelog](https://github.com/getsentry/sentry-symfony/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-symfony/compare/5.2.0...5.3.0)

---
updated-dependencies:
- dependency-name: sentry/sentry-symfony
  dependency-version: 5.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-14 03:00:39 +00:00
bdc13b519e Merge pull request #8366 from wallabag/dependabot/npm_and_yarn/core-js-3.44.0
Bump core-js from 3.43.0 to 3.44.0
2025-07-14 02:29:25 +00:00
365ca09d8e Merge pull request #8365 from wallabag/dependabot/npm_and_yarn/webpack-5.100.1
Bump webpack from 5.99.9 to 5.100.1
2025-07-14 02:25:55 +00:00
9539880690 Bump core-js from 3.43.0 to 3.44.0
Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.43.0 to 3.44.0.
- [Release notes](https://github.com/zloirock/core-js/releases)
- [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/zloirock/core-js/commits/v3.44.0/packages/core-js)

---
updated-dependencies:
- dependency-name: core-js
  dependency-version: 3.44.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-14 02:25:44 +00:00
30f77732e5 Bump webpack from 5.99.9 to 5.100.1
Bumps [webpack](https://github.com/webpack/webpack) from 5.99.9 to 5.100.1.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.99.9...v5.100.1)

---
updated-dependencies:
- dependency-name: webpack
  dependency-version: 5.100.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-14 02:22:21 +00:00
db8acc217e Merge pull request #8339 from skn/master
Add annotations filter to entries API endpoint
2025-07-11 15:07:29 +02:00
9303a2bad8 Merge pull request #8357 from wallabag/dependabot/composer/friendsofphp/php-cs-fixer-3.80.0
Bump friendsofphp/php-cs-fixer from 3.75.0 to 3.80.0
2025-07-11 15:02:42 +02:00
9926868030 Merge pull request #8359 from weblate/weblate-wallabag-messages
Translations update from Hosted Weblate
2025-07-09 09:34:39 +02:00
90e2212b9d Translated using Weblate (Czech)
Currently translated at 100.0% (607 of 607 strings)
2025-07-08 17:01:47 +02:00
62c01abdc7 Merge pull request #8356 from wallabag/dependabot/composer/j0k3r/graby-site-config-1.0.201 2025-07-07 07:02:45 +02:00
27cd2cd190 Bump friendsofphp/php-cs-fixer from 3.75.0 to 3.80.0
Bumps [friendsofphp/php-cs-fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer) from 3.75.0 to 3.80.0.
- [Release notes](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/releases)
- [Changelog](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/compare/v3.75.0...v3.80.0)

---
updated-dependencies:
- dependency-name: friendsofphp/php-cs-fixer
  dependency-version: 3.80.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 02:51:00 +00:00
acc1496f60 Bump j0k3r/graby-site-config from 1.0.200 to 1.0.201
Bumps [j0k3r/graby-site-config](https://github.com/j0k3r/graby-site-config) from 1.0.200 to 1.0.201.
- [Release notes](https://github.com/j0k3r/graby-site-config/releases)
- [Changelog](https://github.com/j0k3r/graby-site-config/blob/master/dallasnews.com.txt)
- [Commits](https://github.com/j0k3r/graby-site-config/compare/1.0.200...1.0.201)

---
updated-dependencies:
- dependency-name: j0k3r/graby-site-config
  dependency-version: 1.0.201
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 02:44:17 +00:00
3e3650a7a8 Merge pull request #8355 from wallabag/dependabot/npm_and_yarn/babel-dependencies-a5859267d5
Bump the babel-dependencies group with 3 updates
2025-07-07 02:21:00 +00:00
be8ea09f74 Bump the babel-dependencies group with 3 updates
Bumps the babel-dependencies group with 3 updates: [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core), [@babel/eslint-parser](https://github.com/babel/babel/tree/HEAD/eslint/babel-eslint-parser) and [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env).


Updates `@babel/core` from 7.27.7 to 7.28.0
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.28.0/packages/babel-core)

Updates `@babel/eslint-parser` from 7.27.5 to 7.28.0
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.28.0/eslint/babel-eslint-parser)

Updates `@babel/preset-env` from 7.27.2 to 7.28.0
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.28.0/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-version: 7.28.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: babel-dependencies
- dependency-name: "@babel/eslint-parser"
  dependency-version: 7.28.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: babel-dependencies
- dependency-name: "@babel/preset-env"
  dependency-version: 7.28.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: babel-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-07 02:17:28 +00:00
ce2ac8f758 Add annotations filter to entries API endpoint
Implement a new filter parameter 'annotations' for the GET /api/entries endpoint
that allows filtering entries based on whether they have annotations. When
annotations=1, only entries with one or more annotations are returned. When
annotations=0, only entries without annotations are returned. This feature
enables users to easily find annotated content through the API.
2025-07-03 20:19:05 +04:00
dbab3c1041 Merge pull request #8290 from wallabag/fix-pocket-csv-controller
Fix PocketCsvController to extend AbstractController
2025-07-02 16:22:37 +02:00
42c87ab1d7 Fix PocketCsvController to extend AbstractController 2025-07-02 16:07:17 +02:00
32 changed files with 951 additions and 451 deletions

2
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1,2 @@
# Migrated rules from dependabot.yml
composer.* @Kdecherf @j0k3r @yguedidi

View File

@ -35,10 +35,6 @@ updates:
phpstan-dependencies:
patterns:
- "phpstan/*"
reviewers:
- j0k3r
- yguedidi
- Kdecherf
ignore:
- dependency-name: symfony/*
update-types: [ "version-update:semver-major" ]

View File

@ -17,7 +17,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
uses: "actions/checkout@v5"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"

View File

@ -41,7 +41,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
uses: "actions/checkout@v5"
with:
fetch-depth: 2
@ -116,7 +116,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
uses: "actions/checkout@v5"
with:
fetch-depth: 2
@ -187,7 +187,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
uses: "actions/checkout@v5"
with:
fetch-depth: 2

View File

@ -22,7 +22,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
uses: "actions/checkout@v5"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"

View File

@ -16,7 +16,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
uses: "actions/checkout@v5"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"

View File

@ -1,6 +1,6 @@
# wallabag
![CI](https://github.com/wallabag/wallabag/workflows/CI/badge.svg)
[![CI](https://github.com/wallabag/wallabag/actions/workflows/continuous-integration.yml/badge.svg?branch=master)](https://github.com/wallabag/wallabag/actions/workflows/continuous-integration.yml?query=branch%3Amaster)
[![Matrix](https://matrix.to/img/matrix-badge.svg)](https://matrix.to/#/#wallabag:matrix.org)
[![Donation Status](https://img.shields.io/liberapay/goal/wallabag.svg?logo=liberapay)](https://liberapay.com/wallabag/donate)
[![Translation status](https://hosted.weblate.org/widgets/wallabag/-/svg-badge.svg)](https://hosted.weblate.org/engage/wallabag/?utm_source=widget)

View File

@ -70,7 +70,7 @@
"doctrine/orm": "^2.20.2",
"doctrine/persistence": "^3.4",
"egulias/email-validator": "^4.0.4",
"enshrined/svg-sanitize": "^0.21",
"enshrined/svg-sanitize": "^0.22",
"friendsofsymfony/jsrouting-bundle": "^3.5",
"friendsofsymfony/oauth-server-bundle": "dev-master#dc8ff343363cf794d30eb1a123610d186a43f162",
"friendsofsymfony/rest-bundle": "^3.8",

138
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "8a12584ee6ea6887963779b321b4860e",
"content-hash": "58a7696a7e938ab8a69c7faf2444cd09",
"packages": [
{
"name": "babdev/pagerfanta-bundle",
@ -1893,16 +1893,16 @@
},
{
"name": "enshrined/svg-sanitize",
"version": "0.21.0",
"version": "0.22.0",
"source": {
"type": "git",
"url": "https://github.com/darylldoyle/svg-sanitizer.git",
"reference": "5e477468fac5c5ce933dce53af3e8e4e58dcccc9"
"reference": "0afa95ea74be155a7bcd6c6fb60c276c39984500"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/5e477468fac5c5ce933dce53af3e8e4e58dcccc9",
"reference": "5e477468fac5c5ce933dce53af3e8e4e58dcccc9",
"url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/0afa95ea74be155a7bcd6c6fb60c276c39984500",
"reference": "0afa95ea74be155a7bcd6c6fb60c276c39984500",
"shasum": ""
},
"require": {
@ -1932,9 +1932,9 @@
"description": "An SVG sanitizer for PHP",
"support": {
"issues": "https://github.com/darylldoyle/svg-sanitizer/issues",
"source": "https://github.com/darylldoyle/svg-sanitizer/tree/0.21.0"
"source": "https://github.com/darylldoyle/svg-sanitizer/tree/0.22.0"
},
"time": "2025-01-13T09:32:25+00:00"
"time": "2025-08-12T10:13:48+00:00"
},
{
"name": "fossar/htmlawed",
@ -4146,16 +4146,16 @@
},
{
"name": "j0k3r/graby-site-config",
"version": "1.0.200",
"version": "1.0.202",
"source": {
"type": "git",
"url": "https://github.com/j0k3r/graby-site-config.git",
"reference": "e9cbbc776a7efcc9c06c07ff360744f266bbfc09"
"reference": "870ff8f1f35cdbf87ff000b68c7bef5e712fd533"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/j0k3r/graby-site-config/zipball/e9cbbc776a7efcc9c06c07ff360744f266bbfc09",
"reference": "e9cbbc776a7efcc9c06c07ff360744f266bbfc09",
"url": "https://api.github.com/repos/j0k3r/graby-site-config/zipball/870ff8f1f35cdbf87ff000b68c7bef5e712fd533",
"reference": "870ff8f1f35cdbf87ff000b68c7bef5e712fd533",
"shasum": ""
},
"require": {
@ -4184,9 +4184,9 @@
"description": "Graby site config files",
"support": {
"issues": "https://github.com/j0k3r/graby-site-config/issues",
"source": "https://github.com/j0k3r/graby-site-config/tree/1.0.200"
"source": "https://github.com/j0k3r/graby-site-config/tree/1.0.202"
},
"time": "2025-06-01T02:42:59+00:00"
"time": "2025-08-01T07:03:24+00:00"
},
{
"name": "j0k3r/httplug-ssrf-plugin",
@ -4405,16 +4405,16 @@
},
{
"name": "jean85/pretty-package-versions",
"version": "2.1.0",
"version": "2.1.1",
"source": {
"type": "git",
"url": "https://github.com/Jean85/pretty-package-versions.git",
"reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10"
"reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/3c4e5f62ba8d7de1734312e4fff32f67a8daaf10",
"reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10",
"url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/4d7aa5dab42e2a76d99559706022885de0e18e1a",
"reference": "4d7aa5dab42e2a76d99559706022885de0e18e1a",
"shasum": ""
},
"require": {
@ -4424,8 +4424,9 @@
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.2",
"jean85/composer-provided-replaced-stub-package": "^1.0",
"phpstan/phpstan": "^1.4",
"phpstan/phpstan": "^2.0",
"phpunit/phpunit": "^7.5|^8.5|^9.6",
"rector/rector": "^2.0",
"vimeo/psalm": "^4.3 || ^5.0"
},
"type": "library",
@ -4458,9 +4459,9 @@
],
"support": {
"issues": "https://github.com/Jean85/pretty-package-versions/issues",
"source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.0"
"source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.1"
},
"time": "2024-11-18T16:19:46+00:00"
"time": "2025-03-19T14:43:43+00:00"
},
{
"name": "jms/metadata",
@ -8049,16 +8050,16 @@
},
{
"name": "sentry/sentry",
"version": "4.10.0",
"version": "4.14.1",
"source": {
"type": "git",
"url": "https://github.com/getsentry/sentry-php.git",
"reference": "2af937d47d8aadb8dab0b1d7b9557e495dd12856"
"reference": "a28c4a6f5fda2bf730789a638501d7a737a64eda"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/getsentry/sentry-php/zipball/2af937d47d8aadb8dab0b1d7b9557e495dd12856",
"reference": "2af937d47d8aadb8dab0b1d7b9557e495dd12856",
"url": "https://api.github.com/repos/getsentry/sentry-php/zipball/a28c4a6f5fda2bf730789a638501d7a737a64eda",
"reference": "a28c4a6f5fda2bf730789a638501d7a737a64eda",
"shasum": ""
},
"require": {
@ -8122,7 +8123,7 @@
],
"support": {
"issues": "https://github.com/getsentry/sentry-php/issues",
"source": "https://github.com/getsentry/sentry-php/tree/4.10.0"
"source": "https://github.com/getsentry/sentry-php/tree/4.14.1"
},
"funding": [
{
@ -8134,27 +8135,27 @@
"type": "custom"
}
],
"time": "2024-11-06T07:44:19+00:00"
"time": "2025-06-23T15:25:52+00:00"
},
{
"name": "sentry/sentry-symfony",
"version": "5.2.0",
"version": "5.3.0",
"source": {
"type": "git",
"url": "https://github.com/getsentry/sentry-symfony.git",
"reference": "394576244d8ac03fd2f305b82d23a6fd7a083b45"
"reference": "5081e7d842424ec09a96e3c79c5b48b89d1195b2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/getsentry/sentry-symfony/zipball/394576244d8ac03fd2f305b82d23a6fd7a083b45",
"reference": "394576244d8ac03fd2f305b82d23a6fd7a083b45",
"url": "https://api.github.com/repos/getsentry/sentry-symfony/zipball/5081e7d842424ec09a96e3c79c5b48b89d1195b2",
"reference": "5081e7d842424ec09a96e3c79c5b48b89d1195b2",
"shasum": ""
},
"require": {
"guzzlehttp/psr7": "^2.1.1",
"jean85/pretty-package-versions": "^1.5||^2.0",
"php": "^7.2||^8.0",
"sentry/sentry": "^4.10.0",
"sentry/sentry": "^4.14.1",
"symfony/cache-contracts": "^1.1||^2.4||^3.0",
"symfony/config": "^4.4.20||^5.0.11||^6.0||^7.0",
"symfony/console": "^4.4.20||^5.0.11||^6.0||^7.0",
@ -8224,7 +8225,7 @@
],
"support": {
"issues": "https://github.com/getsentry/sentry-symfony/issues",
"source": "https://github.com/getsentry/sentry-symfony/tree/5.2.0"
"source": "https://github.com/getsentry/sentry-symfony/tree/5.3.0"
},
"funding": [
{
@ -8236,7 +8237,7 @@
"type": "custom"
}
],
"time": "2025-03-03T07:47:12+00:00"
"time": "2025-07-07T14:14:08+00:00"
},
{
"name": "simplepie/simplepie",
@ -8815,16 +8816,16 @@
},
{
"name": "symfony/cache-contracts",
"version": "v3.5.1",
"version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache-contracts.git",
"reference": "15a4f8e5cd3bce9aeafc882b1acab39ec8de2c1b"
"reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/cache-contracts/zipball/15a4f8e5cd3bce9aeafc882b1acab39ec8de2c1b",
"reference": "15a4f8e5cd3bce9aeafc882b1acab39ec8de2c1b",
"url": "https://api.github.com/repos/symfony/cache-contracts/zipball/5d68a57d66910405e5c0b63d6f0af941e66fc868",
"reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868",
"shasum": ""
},
"require": {
@ -8838,7 +8839,7 @@
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.5-dev"
"dev-main": "3.6-dev"
}
},
"autoload": {
@ -8871,7 +8872,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/cache-contracts/tree/v3.5.1"
"source": "https://github.com/symfony/cache-contracts/tree/v3.6.0"
},
"funding": [
{
@ -8887,7 +8888,7 @@
"type": "tidelift"
}
],
"time": "2024-09-25T14:20:29+00:00"
"time": "2025-03-13T15:25:07+00:00"
},
{
"name": "symfony/config",
@ -15846,58 +15847,59 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.75.0",
"version": "v3.84.0",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "399a128ff2fdaf4281e4e79b755693286cdf325c"
"reference": "38dad0767bf2a9b516b976852200ae722fe984ca"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/399a128ff2fdaf4281e4e79b755693286cdf325c",
"reference": "399a128ff2fdaf4281e4e79b755693286cdf325c",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/38dad0767bf2a9b516b976852200ae722fe984ca",
"reference": "38dad0767bf2a9b516b976852200ae722fe984ca",
"shasum": ""
},
"require": {
"clue/ndjson-react": "^1.0",
"composer/semver": "^3.4",
"composer/xdebug-handler": "^3.0.3",
"composer/xdebug-handler": "^3.0.5",
"ext-filter": "*",
"ext-hash": "*",
"ext-json": "*",
"ext-tokenizer": "*",
"fidry/cpu-core-counter": "^1.2",
"php": "^7.4 || ^8.0",
"react/child-process": "^0.6.5",
"react/child-process": "^0.6.6",
"react/event-loop": "^1.0",
"react/promise": "^2.0 || ^3.0",
"react/promise": "^2.11 || ^3.0",
"react/socket": "^1.0",
"react/stream": "^1.0",
"sebastian/diff": "^4.0 || ^5.1 || ^6.0 || ^7.0",
"symfony/console": "^5.4 || ^6.4 || ^7.0",
"symfony/event-dispatcher": "^5.4 || ^6.4 || ^7.0",
"symfony/filesystem": "^5.4 || ^6.4 || ^7.0",
"symfony/finder": "^5.4 || ^6.4 || ^7.0",
"symfony/options-resolver": "^5.4 || ^6.4 || ^7.0",
"symfony/polyfill-mbstring": "^1.31",
"symfony/polyfill-php80": "^1.31",
"symfony/polyfill-php81": "^1.31",
"symfony/process": "^5.4 || ^6.4 || ^7.2",
"symfony/stopwatch": "^5.4 || ^6.4 || ^7.0"
"sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0",
"symfony/console": "^5.4.45 || ^6.4.13 || ^7.0",
"symfony/event-dispatcher": "^5.4.45 || ^6.4.13 || ^7.0",
"symfony/filesystem": "^5.4.45 || ^6.4.13 || ^7.0",
"symfony/finder": "^5.4.45 || ^6.4.17 || ^7.0",
"symfony/options-resolver": "^5.4.45 || ^6.4.16 || ^7.0",
"symfony/polyfill-mbstring": "^1.32",
"symfony/polyfill-php80": "^1.32",
"symfony/polyfill-php81": "^1.32",
"symfony/process": "^5.4.47 || ^6.4.20 || ^7.2",
"symfony/stopwatch": "^5.4.45 || ^6.4.19 || ^7.0"
},
"require-dev": {
"facile-it/paraunit": "^1.3.1 || ^2.6",
"infection/infection": "^0.29.14",
"justinrainbow/json-schema": "^5.3 || ^6.2",
"keradus/cli-executor": "^2.1",
"justinrainbow/json-schema": "^5.3 || ^6.4",
"keradus/cli-executor": "^2.2",
"mikey179/vfsstream": "^1.6.12",
"php-coveralls/php-coveralls": "^2.7",
"php-coveralls/php-coveralls": "^2.8",
"php-cs-fixer/accessible-object": "^1.1",
"php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6",
"php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6",
"phpunit/phpunit": "^9.6.22 || ^10.5.45 || ^11.5.12",
"symfony/var-dumper": "^5.4.48 || ^6.4.18 || ^7.2.3",
"symfony/yaml": "^5.4.45 || ^6.4.18 || ^7.2.3"
"phpunit/phpunit": "^9.6.23 || ^10.5.47 || ^11.5.25",
"symfony/polyfill-php84": "^1.32",
"symfony/var-dumper": "^5.4.48 || ^6.4.23 || ^7.3.1",
"symfony/yaml": "^5.4.45 || ^6.4.23 || ^7.3.1"
},
"suggest": {
"ext-dom": "For handling output formats in XML",
@ -15938,7 +15940,7 @@
],
"support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.75.0"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.84.0"
},
"funding": [
{
@ -15946,7 +15948,7 @@
"type": "github"
}
],
"time": "2025-03-31T18:40:42+00:00"
"time": "2025-07-15T18:21:57+00:00"
},
{
"name": "friendsoftwig/twigcs",
@ -19453,6 +19455,6 @@
"ext-tokenizer": "*",
"ext-xml": "*"
},
"platform-dev": [],
"plugin-api-version": "2.3.0"
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

View File

@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace Application\Migrations;
use Doctrine\DBAL\Schema\Schema;
use Wallabag\Doctrine\WallabagMigration;
/**
* Add boolean for two-step setup for google authenticator.
*/
final class Version20250413133131 extends WallabagMigration
{
public function up(Schema $schema): void
{
$userTable = $schema->getTable($this->getTable('user'));
$this->skipIf($userTable->hasColumn('google_authenticator'), 'It seems that you already played this migration.');
$userTable->addColumn('google_authenticator', 'boolean', [
'default' => false,
'notnull' => true,
]);
}
/**
* Query to update data in user table, as it's not possible to perform this in the `up` method.
*/
public function postUp(Schema $schema): void
{
$this->skipIf(!$schema->getTable($this->getTable('user'))->hasColumn('google_authenticator'), 'Unable to update google_authenticator column');
$this->connection->executeQuery(
'UPDATE ' . $this->getTable('user') . ' SET google_authenticator = :googleAuthenticator WHERE googleAuthenticatorSecret IS NOT NULL AND googleAuthenticatorSecret <> :emptyString',
[
'googleAuthenticator' => true,
'emptyString' => '',
]
);
}
public function down(Schema $schema): void
{
$userTable = $schema->getTable($this->getTable('user'));
$userTable->dropColumn('google_authenticator');
}
}

View File

@ -41,13 +41,13 @@
"url": "https://github.com/wallabag/wallabag/issues"
},
"devDependencies": {
"@babel/core": "^7.27.7",
"@babel/eslint-parser": "^7.27.5",
"@babel/preset-env": "^7.27.2",
"@babel/core": "^7.28.3",
"@babel/eslint-parser": "^7.28.0",
"@babel/preset-env": "^7.28.3",
"@symfony/webpack-encore": "^5.1.0",
"autoprefixer": "^10.4.21",
"babel-loader": "^10.0.0",
"core-js": "^3.43.0",
"core-js": "^3.45.0",
"css-loader": "^7.1.2",
"eslint": "^8.57.1",
"eslint-config-airbnb-base": "^15.0.0",
@ -55,12 +55,12 @@
"eslint-webpack-plugin": "^5.0.2",
"file-loader": "^6.2.0",
"lato-font": "^3.0.0",
"mini-css-extract-plugin": "^2.9.2",
"mini-css-extract-plugin": "^2.9.4",
"postcss": "^8.5.6",
"postcss-loader": "^8.1.1",
"postcss-scss": "^4.0.9",
"regenerator-runtime": "^0.14.1",
"sass-embedded": "^1.89.2",
"sass-embedded": "^1.90.0",
"sass-loader": "^16.0.5",
"style-loader": "^4.0.0",
"stylelint": "^15.11.0",
@ -69,7 +69,7 @@
"stylelint-scss": "^5.3.2",
"terser-webpack-plugin": "^5.3.14",
"url-loader": "^4.1.1",
"webpack": "^5.99.9",
"webpack": "^5.101.2",
"webpack-cli": "^5.1.4",
"webpack-manifest-plugin": "^5.0.1",
"webpack-merge": "^6.0.1",

View File

@ -290,6 +290,17 @@ class EntryRestController extends WallabagRestController
* example="200",
* )
* ),
* @OA\Parameter(
* name="annotations",
* in="query",
* description="filter entries with annotations. all entries by default",
* required=false,
* @OA\Schema(
* type="integer",
* enum={"1", "0"},
* default="0"
* )
* ),
* @OA\Response(
* response="200",
* description="Returned when successful"
@ -315,6 +326,7 @@ class EntryRestController extends WallabagRestController
$detail = strtolower($request->query->get('detail', 'full'));
$domainName = (null === $request->query->get('domain_name')) ? '' : (string) $request->query->get('domain_name');
$httpStatus = (!\array_key_exists((int) $request->query->get('http_status'), Response::$statusTexts)) ? null : (int) $request->query->get('http_status');
$hasAnnotations = (null === $request->query->get('annotations')) ? null : (bool) $request->query->get('annotations');
try {
/** @var Pagerfanta $pager */
@ -330,7 +342,8 @@ class EntryRestController extends WallabagRestController
$detail,
$domainName,
$isNotParsed,
$httpStatus
$httpStatus,
$hasAnnotations
);
} catch (\Exception $e) {
throw new BadRequestHttpException($e->getMessage());
@ -356,6 +369,7 @@ class EntryRestController extends WallabagRestController
'tags' => $tags,
'since' => $since,
'detail' => $detail,
'annotations' => $hasAnnotations,
],
true
)

View File

@ -313,6 +313,7 @@ class ConfigController extends AbstractController
$user = $this->getUser();
$user->setGoogleAuthenticatorSecret('');
$user->setGoogleAuthenticator(false);
$user->setBackupCodes(null);
$this->userManager->updateUser($user);
@ -354,11 +355,6 @@ class ConfigController extends AbstractController
$this->userManager->updateUser($user);
$this->entityManager->flush();
$this->addFlash(
'notice',
'flashes.config.notice.otp_enabled'
);
return $this->render('Config/otp_app.html.twig', [
'backupCodes' => $backupCodes,
'qr_code' => $googleAuthenticator->getQRContent($user),
@ -408,6 +404,9 @@ class ConfigController extends AbstractController
'notice',
'flashes.config.notice.otp_enabled'
);
$user->setGoogleAuthenticator(true);
$this->userManager->updateUser($user);
$this->entityManager->flush();
return $this->redirect($this->generateUrl('config') . '#set3');
}
@ -421,8 +420,9 @@ class ConfigController extends AbstractController
$user->setBackupCodes(null);
$this->userManager->updateUser($user);
$this->entityManager->flush();
return $this->redirect($this->generateUrl('config') . '#set3');
return $this->redirect($this->generateUrl('config_otp_app'), 307);
}
/**

View File

@ -627,6 +627,16 @@ class EntryController extends AbstractController
$currentEntryId = $request->attributes->getInt('id');
$formOptions = [];
$direction = 'desc';
$sortBy = null;
if (null !== $request->get('entry_filter') && null !== $request->get('entry_filter')['sortType'] && '' !== $request->get('entry_filter')['sortType']) {
$direction = (null !== $request->get('entry_filter')['sortOrder'] && \in_array($request->get('entry_filter')['sortOrder'], ['asc', 'desc'], true)) ? $request->get('entry_filter')['sortOrder'] : 'desc';
if (\in_array($request->get('entry_filter')['sortType'], ['id','title','createdAt', 'url', 'readingTime'], true)) {
$sortBy = $request->get('entry_filter')['sortType'];
}
}
switch ($type) {
case 'search':
@ -654,7 +664,7 @@ class EntryController extends AbstractController
$qb = $this->entryRepository->getBuilderForSameDomainByUser($this->getUser()->getId(), $currentEntryId);
break;
case 'all':
$qb = $this->entryRepository->getBuilderForAllByUser($this->getUser()->getId());
$qb = $this->entryRepository->getBuilderForAllByUser($this->getUser()->getId(), $sortBy, $direction);
break;
default:
throw new \InvalidArgumentException(\sprintf('Type "%s" is not implemented.', $type));

View File

@ -8,10 +8,12 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\Translation\TranslatorInterface;
use Wallabag\Controller\AbstractController;
use Wallabag\Form\Type\UploadImportType;
use Wallabag\Import\PocketCsvImport;
use Wallabag\Redis\Producer as RedisProducer;
class PocketCsvController extends HtmlController
class PocketCsvController extends AbstractController
{
public function __construct(
private readonly PocketCsvImport $pocketCsvImport,
@ -25,7 +27,58 @@ class PocketCsvController extends HtmlController
#[IsGranted('IMPORT_ENTRIES')]
public function indexAction(Request $request, TranslatorInterface $translator)
{
return parent::indexAction($request, $translator);
$form = $this->createForm(UploadImportType::class);
$form->handleRequest($request);
$this->pocketCsvImport->setUser($this->getUser());
if ($this->craueConfig->get('import_with_rabbitmq')) {
$this->pocketCsvImport->setProducer($this->rabbitMqProducer);
} elseif ($this->craueConfig->get('import_with_redis')) {
$this->pocketCsvImport->setProducer($this->redisProducer);
}
if ($form->isSubmitted() && $form->isValid()) {
$file = $form->get('file')->getData();
$markAsRead = $form->get('mark_as_read')->getData();
$name = 'pocket_' . $this->getUser()->getId() . '.csv';
if (null !== $file && \in_array($file->getClientMimeType(), $this->getParameter('wallabag.allow_mimetypes'), true) && $file->move($this->getParameter('wallabag.resource_dir'), $name)) {
$res = $this->pocketCsvImport
->setFilepath($this->getParameter('wallabag.resource_dir') . '/' . $name)
->setMarkAsRead($markAsRead)
->import();
$message = 'flashes.import.notice.failed';
if (true === $res) {
$summary = $this->pocketCsvImport->getSummary();
$message = $translator->trans('flashes.import.notice.summary', [
'%imported%' => $summary['imported'],
'%skipped%' => $summary['skipped'],
]);
if (0 < $summary['queued']) {
$message = $translator->trans('flashes.import.notice.summary_with_queue', [
'%queued%' => $summary['queued'],
]);
}
unlink($this->getParameter('wallabag.resource_dir') . '/' . $name);
}
$this->addFlash('notice', $message);
return $this->redirect($this->generateUrl('homepage'));
}
$this->addFlash('notice', 'flashes.import.notice.failed_on_file');
}
return $this->render('Import/PocketCsv/index.html.twig', [
'form' => $form->createView(),
'import' => $this->pocketCsvImport,
]);
}
protected function getImportService()

View File

@ -147,6 +147,11 @@ class User extends BaseUser implements EmailTwoFactorInterface, GoogleTwoFactorI
#[ORM\Column(name: 'googleAuthenticatorSecret', type: 'string', nullable: true)]
private $googleAuthenticatorSecret;
// default value is explicitly set to false here to ensure that Doctrine
// does not complain about schema mapping mismatch
#[ORM\Column(name: 'google_authenticator', type: 'boolean', options: ['default' => false])]
private $googleAuthenticator = false;
/**
* @var array
*/
@ -264,6 +269,11 @@ class User extends BaseUser implements EmailTwoFactorInterface, GoogleTwoFactorI
$this->emailTwoFactor = $emailTwoFactor;
}
public function setGoogleAuthenticator(bool $googleAuthenticator): void
{
$this->googleAuthenticator = $googleAuthenticator;
}
/**
* Used in the user config form to be "like" the email option.
*/
@ -294,7 +304,7 @@ class User extends BaseUser implements EmailTwoFactorInterface, GoogleTwoFactorI
public function isGoogleAuthenticatorEnabled(): bool
{
return $this->googleAuthenticatorSecret ? true : false;
return $this->googleAuthenticator;
}
public function getGoogleAuthenticatorUsername(): string

View File

@ -205,6 +205,24 @@ class EntryFilterType extends AbstractType
'choices' => array_flip($this->repository->findDistinctLanguageByUser($user->getId())),
'label' => 'entry.filters.language_label',
])
->add('sortOrder', ChoiceFilterType::class, [
'apply_filter' => function (QueryInterface $filterQuery, $field, $values) { },
'choices' => [
'entry.sort.ascending' => 'asc',
'entry.sort.descending' => 'desc',
],
'label' => 'entry.sort.order_label',
])
->add('sortType', ChoiceFilterType::class, [
'apply_filter' => function (QueryInterface $filterQuery, $field, $values) { },
'choices' => [
'entry.sort.by.creation_date' => 'createdAt',
'entry.sort.by.title' => 'title',
'entry.sort.by.url' => 'url',
'entry.sort.by.reading_time' => 'readingTime',
],
'label' => 'entry.sort.status_label',
])
;
}

View File

@ -30,10 +30,11 @@ class EntryRepository extends ServiceEntityRepository
*
* @return QueryBuilder
*/
public function getBuilderForAllByUser($userId)
public function getBuilderForAllByUser($userId, $sortBy = 'createdAt', $direction = 'desc')
{
$sortBy = $sortBy ?: 'createdAt';
return $this
->getSortedQueryBuilderByUser($userId)
->getSortedQueryBuilderByUser($userId, $sortBy, $direction)
;
}
@ -268,16 +269,17 @@ class EntryRepository extends ServiceEntityRepository
* @param string $order
* @param int $since
* @param string $tags
* @param string $detail 'metadata' or 'full'. Include content field if 'full'
* @param string $detail 'metadata' or 'full'. Include content field if 'full'
* @param string $domainName
* @param int $httpStatus
* @param bool $isNotParsed
* @param bool $hasAnnotations
*
* @todo Breaking change: replace default detail=full by detail=metadata in a future version
*
* @return Pagerfanta
*/
public function findEntries($userId, $isArchived = null, $isStarred = null, $isPublic = null, $sort = 'created', $order = 'asc', $since = 0, $tags = '', $detail = 'full', $domainName = '', $isNotParsed = null, $httpStatus = null)
public function findEntries($userId, $isArchived = null, $isStarred = null, $isPublic = null, $sort = 'created', $order = 'asc', $since = 0, $tags = '', $detail = 'full', $domainName = '', $isNotParsed = null, $httpStatus = null, $hasAnnotations = null)
{
if (!\in_array(strtolower($detail), ['full', 'metadata'], true)) {
throw new \Exception('Detail "' . $detail . '" parameter is wrong, allowed: full or metadata');
@ -342,6 +344,16 @@ class EntryRepository extends ServiceEntityRepository
$qb->andWhere('e.domainName = :domainName')->setParameter('domainName', $domainName);
}
if (null !== $hasAnnotations) {
if ($hasAnnotations) {
$qb->leftJoin('e.annotations', 'a')
->andWhere('a.id IS NOT NULL');
} else {
$qb->leftJoin('e.annotations', 'a')
->andWhere('a.id IS NULL');
}
}
if (!\in_array(strtolower($order), ['asc', 'desc'], true)) {
throw new \Exception('Order "' . $order . '" parameter is wrong, allowed: asc or desc');
}

View File

@ -18,14 +18,14 @@
<img data-controller="qrcode" data-qrcode-url-value="{{ qr_code|raw }}" class="hide-on-med-and-down" />
</p>
<div data-controller="highlight">
<div id="config_otp_app_secret">
{{ 'config.otp.app.two_factor_code_description_5'|trans }} <pre><code>{{ secret }}</code></pre>
</div>
</li>
<li>
<p>{{ 'config.otp.app.two_factor_code_description_3'|trans }}</p>
<div data-controller="highlight"><pre><code>{{ backupCodes|join("\n") }}</code></pre></div>
<div><pre><code>{{ backupCodes|join("\n") }}</code></pre></div>
</li>
<li>
<p>{{ 'config.otp.app.two_factor_code_description_4'|trans }}</p>
@ -36,7 +36,7 @@
</div>
{% endfor %}
<form class="form" action="{{ path("config_otp_app_check") }}" method="post">
<form class="form" action="{{ path("config_otp_app_check") }}" method="post" name="config_otp_app_check">
<input type="hidden" name="token" value="{{ csrf_token('otp') }}" />
<div class="card-content">
<div class="row">

View File

@ -21,7 +21,7 @@
<input type="hidden" name="token" value="{{ csrf_token('archive-entry') }}"/>
<button type="submit" class="btn-link tool grey-text" title="{{ 'entry.list.toogle_as_read'|trans }}">
<i class="material-icons">{% if entry.isArchived == 0 %}archive{% else %}unarchive{% endif %}</i>
<i class="material-icons">{% if entry.isArchived == 0 %}done{% else %}unarchive{% endif %}</i>
</button>
</form>
</li>

View File

@ -26,7 +26,7 @@
<input type="hidden" name="token" value="{{ csrf_token('archive-entry') }}"/>
<button type="submit" class="btn-link tool grey-text" title="{{ 'entry.list.toogle_as_read'|trans }}">
<i class="material-icons">{% if entry.isArchived == 0 %}archive{% else %}unarchive{% endif %}</i>
<i class="material-icons">{% if entry.isArchived == 0 %}done{% else %}unarchive{% endif %}</i>
</button>
</form>
{% endif %}

View File

@ -93,7 +93,7 @@
<div class="mass-action">
<div class="mass-action-group">
<input type="checkbox" form="form_mass_action" class="entry-checkbox-input" data-action="batch-edit#toggleSelection" />
<button class="mass-action-button btn cyan darken-1" type="submit" form="form_mass_action" name="toggle-read" title="{{ 'entry.list.toogle_as_read'|trans }}"><i class="material-icons">archive</i></button>
<button class="mass-action-button btn cyan darken-1" type="submit" form="form_mass_action" 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" form="form_mass_action" 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" form="form_mass_action" name="delete" onclick="return confirm('{{ 'entry.confirm.delete_entries'|trans|escape('js') }}')" title="{{ 'entry.list.delete'|trans }}"><i class="material-icons">delete</i></button>
</div>
@ -276,6 +276,22 @@
<label for="entry_filter_createdAt_right_date" class="active">{{ 'entry.filters.created_at.to'|trans }}</label>
</div>
<div class="col s6">
{{ form_label(form.sortType) }}
</div>
<div class="col s6">
{{ form_label(form.sortOrder) }}
</div>
<div class="col s6">
{{ form_widget(form.sortType) }}
</div>
<div class="col s6">
{{ form_widget(form.sortOrder) }}
</div>
<div class="col s6">
<button type="reset" class="center waves-effect waves-green btn-flat">{{ 'entry.filters.action.clear'|trans }}</button>
</div>

View File

@ -31,7 +31,7 @@
<input type="hidden" name="token" value="{{ csrf_token('archive-entry') }}"/>
<button type="submit" class="waves-effect" title="{{ 'entry.view.left_menu.set_as_read'|trans }}">
<i class="material-icons small">{% if entry.isArchived == 0 %}archive{% else %}unarchive{% endif %}</i>
<i class="material-icons small">{% if entry.isArchived == 0 %}done{% else %}unarchive{% endif %}</i>
</button>
</form>
</li>
@ -92,7 +92,7 @@
<input type="hidden" name="token" value="{{ csrf_token('archive-entry') }}"/>
<button type="submit" class="waves-effect collapsible-header markasread" title="{{ mark_as_read_label|trans }}" data-shortcuts-target="markAsRead">
<i class="material-icons small">{% if entry.isArchived == 0 %}archive{% else %}unarchive{% endif %}</i>
<i class="material-icons small">{% if entry.isArchived == 0 %}done{% else %}unarchive{% endif %}</i>
<span>{{ mark_as_read_label|trans }}</span>
</button>
</form>
@ -381,7 +381,7 @@
<input type="hidden" name="token" value="{{ csrf_token('archive-entry') }}"/>
<button type="submit" class="btn-floating">
<i class="material-icons">{% if entry.isArchived == 0 %}archive{% else %}unarchive{% endif %}</i>
<i class="material-icons">{% if entry.isArchived == 0 %}done{% else %}unarchive{% endif %}</i>
</button>
</form>
</li>

View File

@ -20,10 +20,11 @@
<div id="set1" class="col s12">
<dt>{{ 'about.who_behind_wallabag.developped_by'|trans }}</dt>
<dd><a href="mailto:nicolas@loeuillet.org">Nicolas Lœuillet</a> — <a href="https://nicolas.loeuillet.org">{{ 'about.who_behind_wallabag.website'|trans }}</a></dd>
<dd>Nicolas Lœuillet — <a href="https://nicolas.loeuillet.org">{{ 'about.who_behind_wallabag.website'|trans }}</a></dd>
<dd>Thomas Citharel — <a href="https://tcit.fr">{{ 'about.who_behind_wallabag.website'|trans }}</a></dd>
<dd>Jérémy Benoist — <a href="https://www.j0k3r.net">{{ 'about.who_behind_wallabag.website'|trans }}</a></dd>
<dd>Kevin Decherf — <a href="https://kdecherf.com/">{{ 'about.who_behind_wallabag.website'|trans }}</a></dd>
<dd>Yassine Guedidi</dd>
<dt>{{ 'about.who_behind_wallabag.many_contributors'|trans|raw }}</dt>
<dt>{{ 'about.who_behind_wallabag.project_website'|trans }}</dt>
<dd><a href="https://www.wallabag.org">https://www.wallabag.org</a></dd>
@ -33,11 +34,7 @@
<div id="set2" class="col s12">
<dl>
<dt>{{ 'about.getting_help.documentation'|trans }}</dt>
<dd><a href="https://doc.wallabag.org/en/">english</a></dd>
<dd><a href="https://doc.wallabag.org/fr/">français</a></dd>
<dd><a href="https://doc.wallabag.org/de/">deutsch</a></dd>
<dd><a href="https://doc.wallabag.org/it/">italiano</a></dd>
<dt><a href="https://doc.wallabag.org/">{{ 'about.getting_help.documentation'|trans }}</a></dt>
<dt>{{ 'about.getting_help.bug_reports'|trans }}</dt>
<dd>{{ 'about.getting_help.support'|trans|raw }}</dd>

View File

@ -56,7 +56,7 @@
</div>
<div class="card-action">
<ul>
<li><a href="{{ path('import_pocket') }}">{{ 'quickstart.migrate.pocket'|trans }}</a></li>
<li><a href="{{ path('import_pocket_csv') }}">{{ 'quickstart.migrate.pocket'|trans }}</a></li>
<li><a href="{{ path('import_readability') }}">{{ 'quickstart.migrate.readability'|trans }}</a></li>
<li><a href="{{ path('import_instapaper') }}">{{ 'quickstart.migrate.instapaper'|trans }}</a></li>
<li><a href="{{ path('import') }}">{{ 'quickstart.more'|trans }}</a></li>
@ -75,7 +75,6 @@
<div class="card-action">
<ul>
<li><a href="{{ path('developer') }}">{{ 'quickstart.developer.create_application'|trans }}</a></li>
<li><a href="https://doc.wallabag.org/en/developer/docker.html">{{ 'quickstart.developer.use_docker'|trans }}</a></li>
<li><a href="https://doc.wallabag.org/">{{ 'quickstart.more'|trans }}</a></li>
</ul>
</div>

View File

@ -27,7 +27,7 @@
<form class="card-tag-form hidden" data-tag-target="form" action="{{ path('tag_rename', {'slug': tag.slug, redirect: current_path}) }}" method="POST">
{{ form_widget(renameForms[tag.id].label, {'attr': {'value': tag.label, 'data-tag-target': 'input'}}) }}
{{ form_rest(renameForms[tag.id]) }}
<button type="submit"><i class="material-icons">archive</i></button>
<button type="submit"><i class="material-icons">done</i></button>
</form>
<button type="button" data-tag-target="edit" data-action="tag#showForm">
<i class="material-icons">mode_edit</i>

View File

@ -227,6 +227,7 @@ class EntryRestControllerTest extends WallabagApiTestCase
'public' => 0,
'notParsed' => 0,
'http_status' => 200,
'annotations' => 1,
]);
$this->assertSame(200, $this->client->getResponse()->getStatusCode());
@ -254,6 +255,7 @@ class EntryRestControllerTest extends WallabagApiTestCase
$this->assertStringContainsString('tags=foo', $content['_links'][$link]['href']);
$this->assertStringContainsString('since=1443274283', $content['_links'][$link]['href']);
$this->assertStringContainsString('public=0', $content['_links'][$link]['href']);
$this->assertStringContainsString('annotations=1', $content['_links'][$link]['href']);
}
$this->assertSame('application/json', $this->client->getResponse()->headers->get('Content-Type'));
@ -305,6 +307,86 @@ class EntryRestControllerTest extends WallabagApiTestCase
$this->assertSame('application/json', $this->client->getResponse()->headers->get('Content-Type'));
}
public function testGetEntriesWithAnnotationsFilter()
{
// Test filter for entries WITH annotations
// From fixtures: entry1 and entry2 have annotations, entry4, entry5, entry6, entry7 don't
$this->client->request('GET', '/api/entries', [
'annotations' => 1,
]);
$this->assertSame(200, $this->client->getResponse()->getStatusCode());
$content = json_decode($this->client->getResponse()->getContent(), true);
$this->assertArrayHasKey('items', $content['_embedded']);
// Check that only entries with annotations are returned
$entriesWithAnnotations = ['http://0.0.0.0/entry1', 'http://0.0.0.0/entry2'];
$entriesWithoutAnnotations = ['http://0.0.0.0/entry4', 'http://0.0.0.0/entry5', 'http://0.0.0.0/entry6', 'http://0.0.0.0/entry7'];
foreach ($content['_embedded']['items'] as $item) {
if (\in_array($item['url'], $entriesWithAnnotations, true)) {
$this->assertNotEmpty($item['annotations'], 'Entry with URL ' . $item['url'] . ' should have annotations');
}
$this->assertNotContains($item['url'], $entriesWithoutAnnotations, 'Entry without annotations should NOT be in the results');
}
// Ensure we have at least the entries with annotations
$foundUrls = array_column($content['_embedded']['items'], 'url');
$this->assertContains('http://0.0.0.0/entry1', $foundUrls, 'entry1 with annotations should be in the results');
$this->assertContains('http://0.0.0.0/entry2', $foundUrls, 'entry2 with annotations should be in the results');
// Check pagination links contain the filter
$this->assertArrayHasKey('_links', $content);
foreach (['self', 'first', 'last'] as $link) {
$this->assertArrayHasKey('href', $content['_links'][$link]);
$this->assertStringContainsString('annotations=1', $content['_links'][$link]['href']);
}
$this->assertSame('application/json', $this->client->getResponse()->headers->get('Content-Type'));
}
public function testGetEntriesWithoutAnnotationsFilter()
{
// Test filter for entries WITHOUT annotations
// From fixtures: entry1 and entry2 have annotations, entry4, entry5, entry6, entry7 don't
$this->client->request('GET', '/api/entries', [
'annotations' => 0,
]);
$this->assertSame(200, $this->client->getResponse()->getStatusCode());
$content = json_decode($this->client->getResponse()->getContent(), true);
$this->assertArrayHasKey('items', $content['_embedded']);
// Check that only entries without annotations are returned
$entriesWithAnnotations = ['http://0.0.0.0/entry1', 'http://0.0.0.0/entry2'];
$entriesWithoutAnnotations = ['http://0.0.0.0/entry4', 'http://0.0.0.0/entry5', 'http://0.0.0.0/entry6', 'http://0.0.0.0/entry7'];
foreach ($content['_embedded']['items'] as $item) {
$this->assertNotContains($item['url'], $entriesWithAnnotations, 'Entry with annotations should NOT be in the results');
if (\in_array($item['url'], $entriesWithoutAnnotations, true)) {
$this->assertEmpty($item['annotations'], 'Entry with URL ' . $item['url'] . ' should not have annotations');
}
}
// Ensure we have at least some entries without annotations
$foundUrls = array_column($content['_embedded']['items'], 'url');
$foundWithoutAnnotations = array_intersect($foundUrls, $entriesWithoutAnnotations);
$this->assertNotEmpty($foundWithoutAnnotations, 'Should have at least one entry without annotations in the results');
// Check pagination links contain the filter
$this->assertArrayHasKey('_links', $content);
foreach (['self', 'first', 'last'] as $link) {
$this->assertArrayHasKey('href', $content['_links'][$link]);
$this->assertStringContainsString('annotations=0', $content['_links'][$link]['href']);
}
$this->assertSame('application/json', $this->client->getResponse()->headers->get('Content-Type'));
}
public function testGetEntriesOnPageTwo()
{
$this->client->request('GET', '/api/entries', [

View File

@ -3,6 +3,7 @@
namespace Tests\Wallabag\Controller;
use Doctrine\ORM\EntityManagerInterface;
use Scheb\TwoFactorBundle\Security\TwoFactor\Provider\Google\GoogleAuthenticatorInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
@ -1223,27 +1224,74 @@ class ConfigControllerTest extends WallabagTestCase
public function testUserEnable2faGoogle()
{
$googleAuthenticatorMock = $this->createMock(GoogleAuthenticatorInterface::class);
$googleAuthenticatorMock
->method('generateSecret')
->willReturn('DUMMYSECRET');
$googleAuthenticatorMock
->method('checkCode')
->willReturnCallback(function ($user, $code) {
return '123456' === $code;
});
$this->logInAs('admin');
$client = $this->getTestClient();
$client->disableReboot(); // Disable reboot to keep the mock in the container
// name::class notation does not work in this context
self::getContainer()->set('scheb_two_factor.security.google_authenticator', $googleAuthenticatorMock);
$crawler = $client->request('GET', '/config');
$form = $crawler->filter('form[name=config_otp_app]')->form();
$client->submit($form);
$crawler = $client->submit($form);
$this->assertSame(200, $client->getResponse()->getStatusCode());
// restore user
$secret = $crawler->filter('div#config_otp_app_secret pre code')->innerText();
$this->assertSame('DUMMYSECRET', $secret);
$em = $this->getEntityManager();
$user = $em
->getRepository(User::class)
->findOneByUsername('admin');
// At this phase, the user should not have 2FA enabled
$this->assertFalse($user->isGoogleTwoFactor());
// First test: send invalid OTP code
$form = $crawler->filter('form[name=config_otp_app_check]')->form();
$data = [
'_auth_code' => '000000',
];
$client->submit($form, $data);
$this->assertSame(307, $client->getResponse()->getStatusCode());
$this->assertStringContainsString('flashes.config.notice.otp_code_invalid', $client->getContainer()->get(SessionInterface::class)->getFlashBag()->get('notice')[0]);
// Follow the redirect to the OTP check form again
$crawler = $client->followRedirect();
// Second test: send valid OTP code
$form = $crawler->filter('form[name=config_otp_app_check]')->form();
$data = [
'_auth_code' => '123456',
];
$client->submit($form, $data);
$this->assertSame(302, $client->getResponse()->getStatusCode());
$this->assertStringContainsString('flashes.config.notice.otp_enabled', $client->getContainer()->get(SessionInterface::class)->getFlashBag()->get('notice')[0]);
$em = $this->getEntityManager();
$user = $em
->getRepository(User::class)
->findOneByUsername('admin');
$this->assertTrue($user->isGoogleTwoFactor());
$this->assertGreaterThan(0, $user->getBackupCodes());
$this->assertGreaterThan(0, \count($user->getBackupCodes()));
$user->setGoogleAuthenticatorSecret(false);
$user->setBackupCodes(null);
// Restore user
$user->setGoogleAuthenticatorSecret('');
$user->setGoogleAuthenticator(false);
$user->setBackupCodes([]);
$em->persist($user);
$em->flush();
}
@ -1259,6 +1307,7 @@ class ConfigControllerTest extends WallabagTestCase
->findOneByUsername('admin');
$user->setGoogleAuthenticatorSecret('Google2FA');
$user->setGoogleAuthenticator(true);
$em->persist($user);
$em->flush();
@ -1271,7 +1320,6 @@ class ConfigControllerTest extends WallabagTestCase
$this->assertStringContainsString('flashes.config.notice.otp_disabled', $client->getContainer()->get(SessionInterface::class)->getFlashBag()->get('notice')[0]);
// restore user
$em = $this->getEntityManager();
$user = $em
->getRepository(User::class)
@ -1279,6 +1327,7 @@ class ConfigControllerTest extends WallabagTestCase
$this->assertEmpty($user->getGoogleAuthenticatorSecret());
$this->assertEmpty($user->getBackupCodes());
$this->assertFalse($user->isGoogleTwoFactor());
}
public function testExportTaggingRule()

View File

@ -66,6 +66,7 @@ class SecurityControllerTest extends WallabagTestCase
->getRepository(User::class)
->findOneByUsername('admin');
$user->setGoogleAuthenticatorSecret('26LDIHYGHNELOQEM');
$user->setGoogleAuthenticator(true);
$em->persist($user);
$em->flush();
@ -78,6 +79,7 @@ class SecurityControllerTest extends WallabagTestCase
->getRepository(User::class)
->findOneByUsername('admin');
$user->setGoogleAuthenticatorSecret(null);
$user->setGoogleAuthenticator(false);
$em->persist($user);
$em->flush();
}

View File

@ -566,6 +566,7 @@ import:
pocket_csv:
page_title: Import > Pocket CSV
description: Tento importér naimportuje všechny vaše záložky z Pocketu (prostřednictvím CSV exportu). Stačí přejít na https://getpocket.com/export a exportovat soubor. Stáhne se ZIP soubor (např. „pocket.zip“). Po rozbalení získáte CSV soubor, nazvaný „part_000000.csv“.
how_to: Zvolte soubor zálohy záložek a kliknutím na níže uvedené tlačítko jej naimportujte. Pamatujte na to, že tento proces může trvat dlouho, protože je třeba načíst všechny články.
flashes:
config:
notice:

View File

@ -237,6 +237,16 @@ entry:
untagged: Untagged entries
all: All entries
same_domain: Same domain
sort:
status_label: Sort by
order_label: Order
by:
creation_date: Creation date
title: Title
url: URL
reading_time: Reading time
ascending: Ascending
descending: Descending
list:
number_on_the_page: '{0} There are no entries.|{1} There is one entry.|]1,Inf[ There are %count% entries.'
reading_time: estimated reading time

828
yarn.lock

File diff suppressed because it is too large Load Diff