Compare commits

..

1 Commits

Author SHA1 Message Date
66697b29b9 views: escape piwik host and siteId to prevent XSS
Fixes CVE-2018-11352

Signed-off-by: Kevin Decherf <kevin@kdecherf.com>
2018-09-23 22:46:09 +02:00
104 changed files with 1782 additions and 12824 deletions

View File

@ -8,15 +8,9 @@
| Documentation | yes/no
| Translation | yes/no
| CHANGELOG.md | yes/no
| Fixed tickets | #...
| License | MIT
<!--
Please list the issues your PR fixes using special keywords, see
https://help.github.com/articles/closing-issues-using-keywords/
Fixes #…
-->
<!--
- Please fill in this template according to the PR you're about to submit.
- Replace this comment by a description of what your PR is solving.

View File

@ -1,14 +1,17 @@
language: php
services:
- rabbitmq
- redis
- rabbitmq
- redis
# faster builds on docker-container setup
sudo: false
# used for HHVM
addons:
apt:
packages:
- tidy
apt:
packages:
- tidy
# cache vendor dirs
cache:
@ -48,14 +51,6 @@ branches:
except:
- legacy
before_install:
- if [[ $TRAVIS_REPO_SLUG = wallabag/wallabag ]]; then cp .composer-auth.json ~/.composer/auth.json; fi;
install:
- if [[ $ASSETS = build ]]; then source ~/.nvm/nvm.sh && nvm install 6.10; fi;
- if [[ $ASSETS = build ]]; then npm install -g yarn@latest; fi;
- if [[ $ASSETS = build ]]; then yarn install; fi;
before_script:
- PHP=$TRAVIS_PHP_VERSION
- if [[ ! $PHP = hhvm* ]]; then echo "memory_limit=-1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; fi;
@ -63,17 +58,17 @@ before_script:
- if [[ ! $PHP = hhvm* ]]; then phpenv config-rm xdebug.ini || echo "xdebug not available"; fi
- composer self-update --no-progress
- if [[ $DB = pgsql ]]; then psql -c 'create database wallabag_test;' -U postgres; fi;
# increase swap to avoid "proc_open(): fork failed - Cannot allocate memory"
# this should be removed when no more PHP 5 build will be defined
- sudo swapon -s
- sudo fallocate -l 4G /swapfile
- sudo chmod 600 /swapfile
- sudo mkswap /swapfile
- sudo swapon /swapfile
- sudo swapon -s
install:
- if [[ $ASSETS = build ]]; then source ~/.nvm/nvm.sh && nvm install 6.10; fi;
- if [[ $ASSETS = build ]]; then npm install -g yarn@latest; fi;
- if [[ $ASSETS = build ]]; then yarn install; fi;
before_install:
- if [[ $TRAVIS_REPO_SLUG = wallabag/wallabag ]]; then cp .composer-auth.json ~/.composer/auth.json; fi;
script:
- travis_wait bash composer update -o --no-interaction --no-progress --prefer-dist
- travis_wait bash composer install -o --no-interaction --no-progress --prefer-dist
- echo "travis_fold:start:prepare"
- make prepare DB=$DB
- echo "travis_fold:end:prepare"

View File

@ -1,103 +1,5 @@
# Changelog
## [2.3.8](https://github.com/wallabag/wallabag/tree/2.3.8)
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.3.7...2.3.8)
### Fixes
- Jump to 2.3.8-dev [#3897](https://github.com/wallabag/wallabag/pull/3897)
- material: fix left padding on non-entry pages [#3901](https://github.com/wallabag/wallabag/pull/3901)
- Make dev/install/update script posix compatible [#3860](https://github.com/wallabag/wallabag/pull/3860)
- epub: fix exception when articles have the same title [#3908](https://github.com/wallabag/wallabag/pull/3908)
- Fix PHP warning [#3909](https://github.com/wallabag/wallabag/pull/3909)
- Add ability to match many domains for credentials [#3937](https://github.com/wallabag/wallabag/pull/3937)
- material: add metadata to list view [#3942](https://github.com/wallabag/wallabag/pull/3942)
- Enable no-referrer on img tags, enable strict-origin-when-cross-origin by default [#3943](https://github.com/wallabag/wallabag/pull/3943)
- Remove preview picture from share view page#3922
- Fix Intl Locale issue [#3964](https://github.com/wallabag/wallabag/pull/3964)
## [2.3.7](https://github.com/wallabag/wallabag/tree/2.3.7)
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.3.6...2.3.7)
### Fixes
- Jump to 2.3.7-dev [#3837](https://github.com/wallabag/wallabag/pull/3837)
- Fix bad order parameter in the API [#3841](https://github.com/wallabag/wallabag/pull/3841)
- Update composer.json to add php-tidy (ext-tidy) [#3853](https://github.com/wallabag/wallabag/pull/3853)
- Add dedicated email for site config issue [#3861](https://github.com/wallabag/wallabag/pull/3861)
- Fix read & starred status in Pocket import [#3819](https://github.com/wallabag/wallabag/pull/3819)
- Fix broken 2 factor auth logo image [#3869](https://github.com/wallabag/wallabag/pull/3869)
- Fix CORS for API [#3882](https://github.com/wallabag/wallabag/pull/3882)
- Add support of expect parameter to change return object when deleting entry [#3887](https://github.com/wallabag/wallabag/pull/3887)
- epub export: fix missing cover image, only for exports of one article [#3886](https://github.com/wallabag/wallabag/pull/3886)
- Allow optional --ignore-root-warning [#3885](https://github.com/wallabag/wallabag/pull/3885)
- material: fix left padding of content on medium screens [#3893](https://github.com/wallabag/wallabag/pull/3893)
- material: hide creation date from card actions on specific sizes [#3894](https://github.com/wallabag/wallabag/pull/3894)
## [2.3.6](https://github.com/wallabag/wallabag/tree/2.3.6)
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.3.5...2.3.6)
### Fixes
- Jump to 2.3.6-dev and update release process [#3814](https://github.com/wallabag/wallabag/pull/3814)
- Fix tag API leak [#3823](https://github.com/wallabag/wallabag/pull/3823)
- Validate imported entry to avoid error on import [#3816](https://github.com/wallabag/wallabag/pull/3816)
- Fix incorrect reading time calculation for entries with CJK characters [#3820](https://github.com/wallabag/wallabag/pull/3820)
- EntriesExport/epub: replace epub identifier with unique urn [#3827](https://github.com/wallabag/wallabag/pull/3827)
- Fix settings field inverted [#3833](https://github.com/wallabag/wallabag/pull/3833)
- Cast client id to avoid PG error [#3831](https://github.com/wallabag/wallabag/pull/3831)
- Rework of EPUB/PDF exports [#3826](https://github.com/wallabag/wallabag/pull/3826)
## [2.3.5](https://github.com/wallabag/wallabag/tree/2.3.5)
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.3.4...2.3.5)
### Fixes
- Jump to 2.3.5-dev and update release process [#3778](https://github.com/wallabag/wallabag/pull/3778)
- Remove preview picture from single entry view page [#3765](https://github.com/wallabag/wallabag/pull/3765)
- Fix Android app login issue [#3784](https://github.com/wallabag/wallabag/pull/3784)
- material: fix missing thumbnail on list view [#3782](https://github.com/wallabag/wallabag/pull/3782)
- material: decrease size of tags on list view [#3783](https://github.com/wallabag/wallabag/pull/3783)
- build: upgrade yarn dependencies, update prod assets [#3781](https://github.com/wallabag/wallabag/pull/3781)
- No more dev for guzzle-site-authenticator [#3810](https://github.com/wallabag/wallabag/pull/3810)
## [2.3.4](https://github.com/wallabag/wallabag/tree/2.3.4)
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.3.3...2.3.4)
### Fixes
- Fix image downloading on null image path [#3684](https://github.com/wallabag/wallabag/pull/3684)
- Remove remaining deprecation notices [#3686](https://github.com/wallabag/wallabag/pull/3686)
- Fix mobile viewport on big iframe and video elements [#3683](https://github.com/wallabag/wallabag/pull/3683)
- Autofocus the username field on the login page [#3691](https://github.com/wallabag/wallabag/pull/3691)
- Feature/svg logo [#3692](https://github.com/wallabag/wallabag/pull/3692)
- Fixes a typo [#3702](https://github.com/wallabag/wallabag/pull/3702)
- Update release script [#3705](https://github.com/wallabag/wallabag/pull/3705)
- Removing failing test from Travis [#3707](https://github.com/wallabag/wallabag/pull/3707)
- Replace SO url by lemonde.fr to avoid random failing test [#3685](https://github.com/wallabag/wallabag/pull/3685)
- php-cs-fixer: native_function_invocation [#3716](https://github.com/wallabag/wallabag/pull/3716)
- PHP 7.2 shouldn't fail [#3717](https://github.com/wallabag/wallabag/pull/3717)
- Liberation goes https [#3726](https://github.com/wallabag/wallabag/pull/3726)
- Bugfix: Sanitize the title of a saved webpage from invalid UTF-8 characters. [#3725](https://github.com/wallabag/wallabag/pull/3725)
- Fix dockerfile php72 [#3734](https://github.com/wallabag/wallabag/pull/3734)
- Fix sort parameters [#3719](https://github.com/wallabag/wallabag/pull/3719)
- Add note on GitHub PR template to auto-close issues [#3763](https://github.com/wallabag/wallabag/pull/3763)
- Fix link to wallabag requirements in documentation [#3766](https://github.com/wallabag/wallabag/pull/3766)
- Update translation when marking as read [#3772](https://github.com/wallabag/wallabag/pull/3772)
- Makefile fixes for non GNU systems [#3706](https://github.com/wallabag/wallabag/pull/3706)
- Card no preview replaced by wallabag logo [#3774](https://github.com/wallabag/wallabag/pull/3774)
### Changes
- Propose YunoHost badge for installing [#3678](https://github.com/wallabag/wallabag/pull/3678)
- More robust srcset image attribute handling [#3690](https://github.com/wallabag/wallabag/pull/3690)
- Rename getBuilderByUser and refactor query for untagged entries [#3712](https://github.com/wallabag/wallabag/pull/3712)
- Show tags on non-image gallery preview card [#3743](https://github.com/wallabag/wallabag/pull/3743)
- add manifest.json for android pwa [#3606](https://github.com/wallabag/wallabag/pull/3606)
- Add placeholder image to card-based gallery entries page [#3745](https://github.com/wallabag/wallabag/pull/3745)
- Abort running install and update script if root [#3733](https://github.com/wallabag/wallabag/pull/3733)
- Swap entry url with origin url if graby provides an updated one [#3553](https://github.com/wallabag/wallabag/pull/3553)
## [2.3.3](https://github.com/wallabag/wallabag/tree/2.3.3)
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.3.2...2.3.3)

View File

@ -1,53 +0,0 @@
SHELL=bash
TMP_FOLDER=/tmp
RELEASE_FOLDER=wllbg-release
ENV ?= prod
help: ## Display this help menu
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
clean: ## Clear the application cache
rm -rf var/cache/*
install: ## Install wallabag with the latest version
@./scripts/install.sh $(ENV)
update: ## Update the wallabag installation to the latest version
@./scripts/update.sh $(ENV)
dev: ## Install the latest dev version
@./scripts/dev.sh
run: ## Run the wallabag built-in server
@php bin/console server:run --env=dev
build: ## Run webpack
@npm run build:$(ENV)
prepare: clean ## Prepare database for testsuite
ifdef DB
cp app/config/tests/parameters_test.$(DB).yml app/config/parameters_test.yml
endif
-php bin/console doctrine:database:drop --force --env=test
php bin/console doctrine:database:create --env=test
php bin/console doctrine:migrations:migrate --no-interaction --env=test
fixtures: ## Load fixtures into database
php bin/console doctrine:fixtures:load --no-interaction --env=test
test: prepare fixtures ## Launch wallabag testsuite
bin/simple-phpunit -v
release: ## Create a package. Need a VERSION parameter (eg: `make release VERSION=master`).
ifndef VERSION
$(error VERSION is not set)
endif
@./scripts/release.sh $(VERSION) $(TMP_FOLDER) $(RELEASE_FOLDER) $(ENV)
deploy: ## Deploy wallabag
@bundle exec cap staging deploy
.PHONY: help clean prepare install fixtures update build test release deploy run dev
.DEFAULT_GOAL := install

54
Makefile Normal file → Executable file
View File

@ -1,2 +1,52 @@
.DEFAULT:
gmake $@
TMP_FOLDER=/tmp
RELEASE_FOLDER=wllbg-release
ENV ?= prod
help: ## Display this help menu
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
clean: ## Clear the application cache
rm -rf var/cache/*
install: ## Install wallabag with the latest version
@sh scripts/install.sh $(ENV)
update: ## Update the wallabag installation to the latest version
@sh scripts/update.sh $(ENV)
dev: ## Install the latest dev version
@sh scripts/dev.sh
run: ## Run the wallabag built-in server
@php bin/console server:run --env=dev
build: ## Run webpack
@npm run build:$(ENV)
prepare: clean ## Prepare database for testsuite
ifdef DB
cp app/config/tests/parameters_test.$(DB).yml app/config/parameters_test.yml
endif
-php bin/console doctrine:database:drop --force --env=test
php bin/console doctrine:database:create --env=test
php bin/console doctrine:migrations:migrate --no-interaction --env=test
fixtures: ## Load fixtures into database
php bin/console doctrine:fixtures:load --no-interaction --env=test
test: prepare fixtures ## Launch wallabag testsuite
bin/simple-phpunit -v
release: ## Create a package. Need a VERSION parameter (eg: `make release VERSION=master`).
ifndef VERSION
$(error VERSION is not set)
endif
@sh scripts/release.sh $(VERSION) $(TMP_FOLDER) $(RELEASE_FOLDER) $(ENV)
deploy: ## Deploy wallabag
@bundle exec cap staging deploy
.PHONY: help clean prepare install fixtures update build test release deploy run dev
.DEFAULT_GOAL := install

View File

@ -13,7 +13,7 @@ If you do not have your own server, consider [the wallabag.it hosting solution](
![wallabag logo](https://raw.githubusercontent.com/wallabag/logo/master/_default/typo-horizontal/png/sm/logo-typo-horizontal-black-no-bg-no-border-sm.png)
# Install wallabag
Please read [the documentation to see the wallabag requirements](https://doc.wallabag.org/en/admin/installation/requirements.html).
Please read [the documentation to see the wallabag requirements](http://doc.wallabag.org/en/master/user/installation.html#requirements).
Then you can install wallabag by executing the following commands:

View File

@ -4,17 +4,14 @@ A release is mostly a git tag of http://github.com/wallabag/wallabag, following
### Steps to release
During this documentation, we assume the release is `$LAST_WALLABAG_RELEASE` (like 2.3.4).
During this documentation, we assume the release is `$LAST_WALLABAG_RELEASE`.
#### Prepare the release
#### Files to edit
- Update these files with new information
- `app/config/wallabag.yml` (`wallabag_core.version`)
- `CHANGELOG.md`
- Create a PR named "Prepare $LAST_WALLABAG_RELEASE release".
- Wait for test to be ok, merge it.
- `app/config/wallabag.yml` (`wallabag_core.version`)
- `CHANGELOG.md`
#### Create a new release on GitHub
#### Create release on GitHub
- Run these commands to create the tag:
@ -29,8 +26,8 @@ SYMFONY_ENV=prod composer up --no-dev
```diff
script:
- - travis_wait bash composer install -o --no-interaction --no-progress --prefer-dist
+ - travis_wait bash composer update -o --no-interaction --no-progress --prefer-dist
- - travis_wait bash composer install -o --no-interaction --no-progress --prefer-dist
+ - travis_wait composer update --no-interaction --no-progress
```
- Then continue with these commands:
@ -45,15 +42,16 @@ git push origin release-$LAST_WALLABAG_RELEASE
- Run these command to create the package:
```
make release VERSION=$LAST_WALLABAG_RELEASE
make release master /tmp wllbg-release prod
```
- [Create the new release on GitHub](https://github.com/wallabag/wallabag/releases/new) by targetting the `release-$LAST_WALLABAG_RELEASE` branch. You have to upload the package (generated previously).
- Close the previously created pull request (**DO NOT MERGE IT**) and delete the `release-$LAST_WALLABAG_RELEASE` branch.
- [Create the new release on GitHub](https://github.com/wallabag/wallabag/releases/new). You have to upload on this page the package.
- Delete the `release-$LAST_WALLABAG_RELEASE` branch and close the pull request (**DO NOT MERGE IT**).
- Update the URL shortener (used on `wllbg.org` to generate links like `https://wllbg.org/latest-v2-package` or `http://wllbg.org/latest-v2`)
- Update [the downloads page](https://github.com/wallabag/wallabag.org/blob/master/content/pages/download.md) on the website (MD5 sum, release date)
- Update Dockerfile https://github.com/wallabag/docker (and create a new tag)
- Update wallabag.org website (downloads, MD5 sum, releases and new blog post)
- Put the next patch version suffixed with `-dev` in `app/config/wallabag.yml` (`wallabag_core.version`)
- Update wallabag.org website (downloads, releases and new blog post)
- Put the next patch version suffixed with `-dev` in `app/config/config.yml` (`wallabag_core.version`)
- Drink a :beer:!
### `composer.lock`

View File

@ -18,24 +18,6 @@ main {
overflow: hidden;
}
@mixin mixin-reading-time {
.reading-time {
display: inline-flex;
vertical-align: middle;
.card-reading-time,
.card-created-at {
display: inline-flex;
}
span {
margin-right: 5px;
}
@content;
}
}
.card {
.card-content .card-title,
.card-reveal .card-title {
@ -116,7 +98,14 @@ main {
margin-right: 5px !important;
}
@include mixin-reading-time;
.reading-time {
display: inline-flex;
vertical-align: middle;
span {
margin-right: 5px;
}
}
}
.card-image {
@ -127,6 +116,13 @@ main {
height: 13.5em;
}
.card-image .preview,
.card-fullimage .preview {
height: 14em;
background: no-repeat 50%/cover;
display: block;
}
&.sw {
max-width: 370px;
margin-left: auto;
@ -141,19 +137,6 @@ a.original:not(.waves-effect) {
display: block;
}
.card .card-image .preview,
.card .card-fullimage .preview,
.card-stacked .preview {
height: 100%;
background: no-repeat 50%/cover;
background-color: #efefef;
display: block;
&--default {
background-size: contain;
}
}
.card-entry-labels li,
.card-tag-labels li {
margin: 10px 10px 10px auto;
@ -222,29 +205,24 @@ a.original:not(.waves-effect) {
text-align: right;
}
.card-preview {
.preview {
max-width: 100px;
max-height: 50px;
height: auto;
margin-right: 10px;
flex: 1;
img {
max-width: 100%;
max-height: 100%;
}
}
div.metadata {
overflow: hidden;
height: 1.5em;
display: flex;
ul.tags {
margin-left: 4px;
}
.chip {
background-color: $blueAccentColor;
padding: 0 7px;
margin: auto 1px;
padding: 0 15px 0 10px;
margin: auto 2px;
border-radius: 6px;
line-height: 22px;
height: 22px;
a,
i {
@ -258,16 +236,6 @@ a.original:not(.waves-effect) {
padding-left: 8px;
}
}
@include mixin-reading-time {
padding: 0 5px;
flex-wrap: wrap;
margin-left: auto;
i.material-icons {
font-size: 20px;
}
}
}
div.card-content {
@ -301,3 +269,9 @@ a.original:not(.waves-effect) {
.settings .div_tabs {
padding-bottom: 15px;
}
@media only screen and (min-width: 992px) {
.card-tag-labels li {
max-width: 50%;
}
}

View File

@ -12,16 +12,6 @@
.pagination {
margin-left: auto;
}
.card-tag-labels li {
max-width: 50%;
}
}
@media screen and (min-width: 993px) {
body.entry main #content {
padding-left: 70px;
}
}
@media only screen and (max-width: 992px) {
@ -173,17 +163,4 @@
.row .col {
padding: 0;
}
.card-stacked div.metadata .reading-time {
display: none;
}
}
@media screen and (max-width: 310px),
screen and (min-width: 601px) and (max-width: 660px),
screen and (min-width: 993px) and (max-width: 1050px),
screen and (min-width: 1201px) and (max-width: 1250px) {
.card .card-action .reading-time .card-created-at {
display: none;
}
}

View File

@ -147,18 +147,18 @@ nelmio_cors:
paths:
'^/api/':
allow_origin: ['*']
allow_headers: ['Authorization','content-type']
allow_headers: ['X-Custom-Auth']
allow_methods: ['POST', 'PUT', 'PATCH','GET', 'DELETE']
max_age: 3600
'^/oauth/':
allow_origin: ['*']
allow_headers: ['Authorization','content-type']
allow_headers: ['X-Custom-Auth']
allow_methods: ['POST', 'PUT', 'GET', 'DELETE']
max_age: 3600
'^/':
#origin_regex: true
allow_origin: ['*']
allow_headers: ['Authorization','content-type']
allow_origin: ['^http://localhost:[0-9]+']
allow_headers: ['X-Custom-Auth']
allow_methods: ['POST', 'PUT', 'GET', 'DELETE']
max_age: 3600
hosts: ['^api\.']

View File

@ -1,5 +1,5 @@
wallabag_core:
version: 2.3.8
version: 2.3.3
paypal_url: "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=9UBA65LG3FX9Y&lc=gb"
languages:
en: 'English'

View File

@ -43,7 +43,6 @@
"ext-iconv": "*",
"ext-tokenizer": "*",
"ext-pdo": "*",
"ext-tidy": "*",
"symfony/symfony": "~3.3.13",
"doctrine/orm": "^2.5.12",
"doctrine/doctrine-bundle": "^1.8.0",
@ -84,16 +83,15 @@
"javibravo/simpleue": "^2.0",
"symfony/dom-crawler": "^3.3.13",
"friendsofsymfony/jsrouting-bundle": "^1.6.3",
"bdunogier/guzzle-site-authenticator": "^1.0.0",
"bdunogier/guzzle-site-authenticator": "^1.0.0@dev",
"defuse/php-encryption": "^2.1",
"html2text/html2text": "^4.1",
"sulu/symfony-intl-fix": "^1.0"
"html2text/html2text": "^4.1"
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "~2.2",
"doctrine/data-fixtures": "~1.1",
"sensio/generator-bundle": "^3.0",
"symfony/phpunit-bridge": "^4.2",
"symfony/phpunit-bridge": "^3.3",
"friendsofphp/php-cs-fixer": "~2.0",
"m6web/redis-mock": "^2.0",
"dama/doctrine-test-bundle": "^4.0"
@ -126,11 +124,7 @@
},
"autoload": {
"psr-4": { "Wallabag\\": "src/Wallabag/" },
"classmap": [ "app/AppKernel.php", "app/AppCache.php" ],
"exclude-from-classmap": [
"vendor/symfony/intl/Locale.php",
"vendor/symfony/symfony/src/Symfony/Component/Intl/Locale.php"
]
"classmap": [ "app/AppKernel.php", "app/AppCache.php" ]
},
"autoload-dev": {
"psr-4": { "Tests\\": "tests/" }

7748
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -4,10 +4,10 @@ FROM php:fpm
ARG timezone='Europe/Paris'
RUN apt-get update && apt-get install -y \
libmcrypt-dev libicu-dev libpq-dev libxml2-dev libpng-dev libjpeg-dev \
libmcrypt-dev libicu-dev libpq-dev libxml2-dev libpng12-dev libjpeg-dev \
&& /usr/local/bin/docker-php-ext-configure gd --with-jpeg-dir=/usr/include \
&& docker-php-ext-install \
iconv mbstring intl pdo pdo_mysql pdo_pgsql gd
iconv mcrypt mbstring intl pdo pdo_mysql pdo_pgsql gd
RUN echo "date.timezone="$timezone > /usr/local/etc/php/conf.d/date_timezone.ini

10
scripts/dev.sh Executable file → Normal file
View File

@ -3,14 +3,10 @@
# eg: `sh dev.sh`
COMPOSER_COMMAND='composer'
REQUIRE_FILE='scripts/require.sh'
if [ ! -f "$REQUIRE_FILE" ]; then
echo "Cannot find $REQUIRE_FILE"
exit 1
fi
. "$REQUIRE_FILE"
DIR="${BASH_SOURCE}"
if [ ! -d "$DIR" ]; then DIR="$PWD/scripts"; fi
. "$DIR/require.sh"
$COMPOSER_COMMAND install
php bin/console wallabag:install

33
scripts/install.sh Executable file → Normal file
View File

@ -2,38 +2,13 @@
# You can execute this file to install wallabag
# eg: `sh install.sh prod`
IGNORE_ROOT_ARG="--ignore-root-warning"
IGNORE_ROOT=0
while :; do
case $1 in
$IGNORE_ROOT_ARG) IGNORE_ROOT=1
;;
*[a-zA-Z]) ENV=$1
;;
*) break
;;
esac
shift
done
# Abort running this script if root
if [ "$IGNORE_ROOT" -eq 0 ] && [ "$EUID" == "0" ]; then
echo "Do not run this script as root!" >&2
echo "Use $IGNORE_ROOT_ARG to ignore this error." >&2
exit 1
fi
COMPOSER_COMMAND='composer'
REQUIRE_FILE='scripts/require.sh'
if [ ! -f "$REQUIRE_FILE" ]; then
echo "Cannot find $REQUIRE_FILE"
exit 1
fi
. "$REQUIRE_FILE"
DIR="${BASH_SOURCE}"
if [ ! -d "$DIR" ]; then DIR="$PWD/scripts"; fi
. "$DIR/require.sh"
ENV=$1
TAG=$(git describe --tags $(git rev-list --tags --max-count=1))
git checkout $TAG

4
scripts/release.sh Executable file → Normal file
View File

@ -9,9 +9,9 @@ ENV=$4
rm -rf $TMP_FOLDER/$RELEASE_FOLDER
mkdir $TMP_FOLDER/$RELEASE_FOLDER
git clone git@github.com:wallabag/wallabag.git -b release-$VERSION $TMP_FOLDER/$RELEASE_FOLDER/$VERSION
git clone git@github.com:wallabag/wallabag.git -b $VERSION $TMP_FOLDER/$RELEASE_FOLDER/$VERSION
cd $TMP_FOLDER/$RELEASE_FOLDER/$VERSION && SYMFONY_ENV=$ENV COMPOSER_MEMORY_LIMIT=-1 composer up -n --no-dev
cd $TMP_FOLDER/$RELEASE_FOLDER/$VERSION && php bin/console wallabag:install --env=$ENV -n
cd $TMP_FOLDER/$RELEASE_FOLDER/$VERSION && php bin/console wallabag:install --env=$ENV
cd $TMP_FOLDER/$RELEASE_FOLDER/$VERSION && php bin/console assets:install --env=$ENV --symlink --relative
cd $TMP_FOLDER/$RELEASE_FOLDER && tar czf wallabag-$VERSION.tar.gz --exclude="var/cache/*" --exclude="var/logs/*" --exclude="var/sessions/*" --exclude=".git" $VERSION
echo "MD5 checksum of the package for wallabag $VERSION"

0
scripts/require.sh Executable file → Normal file
View File

32
scripts/update.sh Executable file → Normal file
View File

@ -2,40 +2,16 @@
# You can execute this file to update wallabag
# eg: `sh update.sh prod`
IGNORE_ROOT_ARG="--ignore-root-warning"
IGNORE_ROOT=0
while :; do
case $1 in
$IGNORE_ROOT_ARG) IGNORE_ROOT=1
;;
*[a-zA-Z]) ENV=$1
;;
*) break
;;
esac
shift
done
# Abort running this script if root
if [ "$IGNORE_ROOT" -eq 0 ] && [ "$EUID" == "0" ]; then
echo "Do not run this script as root!" >&2
echo "Use $IGNORE_ROOT_ARG to ignore this error." >&2
exit 1
fi
set -e
set -u
COMPOSER_COMMAND='composer'
REQUIRE_FILE='scripts/require.sh'
if [ ! -f "$REQUIRE_FILE" ]; then
echo "Cannot find $REQUIRE_FILE"
exit 1
fi
DIR="${BASH_SOURCE}"
if [ ! -d "$DIR" ]; then DIR="$PWD/scripts"; fi
. "$DIR/require.sh"
. "$REQUIRE_FILE"
ENV=$1
rm -rf var/cache/*
git fetch origin

View File

@ -9,7 +9,6 @@ use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Wallabag\CoreBundle\Entity\Entry;
@ -99,28 +98,24 @@ class EntryRestController extends WallabagRestController
$isArchived = (null === $request->query->get('archive')) ? null : (bool) $request->query->get('archive');
$isStarred = (null === $request->query->get('starred')) ? null : (bool) $request->query->get('starred');
$isPublic = (null === $request->query->get('public')) ? null : (bool) $request->query->get('public');
$sort = strtolower($request->query->get('sort', 'created'));
$order = strtolower($request->query->get('order', 'desc'));
$sort = $request->query->get('sort', 'created');
$order = $request->query->get('order', 'desc');
$page = (int) $request->query->get('page', 1);
$perPage = (int) $request->query->get('perPage', 30);
$tags = \is_array($request->query->get('tags')) ? '' : (string) $request->query->get('tags', '');
$since = $request->query->get('since', 0);
try {
/** @var \Pagerfanta\Pagerfanta $pager */
$pager = $this->get('wallabag_core.entry_repository')->findEntries(
$this->getUser()->getId(),
$isArchived,
$isStarred,
$isPublic,
$sort,
$order,
$since,
$tags
);
} catch (\Exception $e) {
throw new BadRequestHttpException($e->getMessage());
}
/** @var \Pagerfanta\Pagerfanta $pager */
$pager = $this->get('wallabag_core.entry_repository')->findEntries(
$this->getUser()->getId(),
$isArchived,
$isStarred,
$isPublic,
$sort,
$order,
$since,
$tags
);
$pager->setMaxPerPage($perPage);
$pager->setCurrentPage($page);
@ -570,31 +565,18 @@ class EntryRestController extends WallabagRestController
* @ApiDoc(
* requirements={
* {"name"="entry", "dataType"="integer", "requirement"="\w+", "description"="The entry ID"}
* },
* parameters={
* {"name"="expect", "dataType"="string", "required"=false, "format"="id or entry", "description"="Only returns the id instead of the deleted entry's full entity if 'id' is specified. Default to entry"},
* }
* )
*
* @return JsonResponse
*/
public function deleteEntriesAction(Entry $entry, Request $request)
public function deleteEntriesAction(Entry $entry)
{
$expect = $request->query->get('expect', 'entry');
if (!\in_array($expect, ['id', 'entry'], true)) {
throw new BadRequestHttpException(sprintf("expect: 'id' or 'entry' expected, %s given", $expect));
}
$this->validateAuthentication();
$this->validateUserAccess($entry->getUser()->getId());
$response = $this->sendResponse([
'id' => $entry->getId(),
]);
// We clone $entry to keep id in returned object
if ('entry' === $expect) {
$e = clone $entry;
$response = $this->sendResponse($e);
}
// We copy $entry to keep id in returned object
$e = $entry;
$em = $this->getDoctrine()->getManager();
$em->remove($entry);
@ -603,7 +585,7 @@ class EntryRestController extends WallabagRestController
// entry deleted, dispatch event about it!
$this->get('event_dispatcher')->dispatch(EntryDeletedEvent::NAME, new EntryDeletedEvent($entry));
return $response;
return $this->sendResponse($e);
}
/**

View File

@ -46,14 +46,12 @@ class TagRestController extends WallabagRestController
$this->validateAuthentication();
$label = $request->get('tag', '');
$tags = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findByLabelsAndUser([$label], $this->getUser()->getId());
$tag = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findOneByLabel($label);
if (empty($tags)) {
if (empty($tag)) {
throw $this->createNotFoundException('Tag not found');
}
$tag = $tags[0];
$this->getDoctrine()
->getRepository('WallabagCoreBundle:Entry')
->removeTag($this->getUser()->getId(), $tag);
@ -82,7 +80,15 @@ class TagRestController extends WallabagRestController
$tagsLabels = $request->get('tags', '');
$tags = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findByLabelsAndUser(explode(',', $tagsLabels), $this->getUser()->getId());
$tags = [];
foreach (explode(',', $tagsLabels) as $tagLabel) {
$tagEntity = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findOneByLabel($tagLabel);
if (!empty($tagEntity)) {
$tags[] = $tagEntity;
}
}
if (empty($tags)) {
throw $this->createNotFoundException('Tags not found');
@ -114,12 +120,6 @@ class TagRestController extends WallabagRestController
{
$this->validateAuthentication();
$tagFromDb = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findByLabelsAndUser([$tag->getLabel()], $this->getUser()->getId());
if (empty($tagFromDb)) {
throw $this->createNotFoundException('Tag not found');
}
$this->getDoctrine()
->getRepository('WallabagCoreBundle:Entry')
->removeTag($this->getUser()->getId(), $tag);

View File

@ -11,7 +11,7 @@ use Wallabag\UserBundle\Entity\User;
/**
* @ORM\Table("oauth2_clients")
* @ORM\Entity(repositoryClass="Wallabag\ApiBundle\Repository\ClientRepository")
* @ORM\Entity
*/
class Client extends BaseClient
{

View File

@ -1,19 +0,0 @@
<?php
namespace Wallabag\ApiBundle\Repository;
use Doctrine\ORM\EntityRepository;
class ClientRepository extends EntityRepository
{
public function findOneBy(array $criteria, array $orderBy = null)
{
if (!empty($criteria['id'])) {
// cast client id to be an integer to avoid postgres error:
// "invalid input syntax for integer"
$criteria['id'] = (int) $criteria['id'];
}
return parent::findOneBy($criteria, $orderBy);
}
}

View File

@ -58,7 +58,6 @@ class ExportController extends Controller
$method = ucfirst($category);
$methodBuilder = 'getBuilderFor' . $method . 'ByUser';
$repository = $this->get('wallabag_core.entry_repository');
$title = $method;
if ('tag_entries' === $category) {
$tag = $this->get('wallabag_core.tag_repository')->findOneBySlug($request->query->get('tag'));
@ -67,8 +66,6 @@ class ExportController extends Controller
$this->getUser()->getId(),
$tag->getId()
);
$title = 'Tag ' . $tag->getLabel();
} else {
$entries = $repository
->$methodBuilder($this->getUser()->getId())
@ -79,7 +76,7 @@ class ExportController extends Controller
try {
return $this->get('wallabag_core.helper.entries_export')
->setEntries($entries)
->updateTitle($title)
->updateTitle($method)
->updateAuthor($method)
->exportAs($format);
} catch (\InvalidArgumentException $e) {

View File

@ -14,112 +14,97 @@ class LoadEntryData extends AbstractFixture implements OrderedFixtureInterface
*/
public function load(ObjectManager $manager)
{
$entries = [
'entry1' => [
'user' => 'admin-user',
'url' => 'http://0.0.0.0/entry1',
'reading_time' => 11,
'domain' => 'domain.io',
'mime' => 'text/html',
'title' => 'test title entry1',
'content' => 'This is my content /o/',
'language' => 'en',
'tags' => ['foo-tag', 'baz-tag'],
],
'entry2' => [
'user' => 'admin-user',
'url' => 'http://0.0.0.0/entry2',
'reading_time' => 1,
'domain' => 'domain.io',
'mime' => 'text/html',
'title' => 'test title entry2',
'content' => 'This is my content /o/',
'origin' => 'ftp://oneftp.tld',
'language' => 'fr',
],
'entry3' => [
'user' => 'bob-user',
'url' => 'http://0.0.0.0/entry3',
'reading_time' => 1,
'domain' => 'domain.io',
'mime' => 'text/html',
'title' => 'test title entry3',
'content' => 'This is my content /o/',
'language' => 'en',
'tags' => ['foo-tag', 'bar-tag', 'bob-tag'],
],
'entry4' => [
'user' => 'admin-user',
'url' => 'http://0.0.0.0/entry4',
'reading_time' => 12,
'domain' => 'domain.io',
'mime' => 'text/html',
'title' => 'test title entry4',
'content' => 'This is my content /o/',
'language' => 'en',
'tags' => ['foo-tag', 'bar-tag'],
],
'entry5' => [
'user' => 'admin-user',
'url' => 'http://0.0.0.0/entry5',
'reading_time' => 12,
'domain' => 'domain.io',
'mime' => 'text/html',
'title' => 'test title entry5',
'content' => 'This is my content /o/',
'language' => 'fr',
'starred' => true,
'preview' => 'http://0.0.0.0/image.jpg',
],
'entry6' => [
'user' => 'admin-user',
'url' => 'http://0.0.0.0/entry6',
'reading_time' => 12,
'domain' => 'domain.io',
'mime' => 'text/html',
'title' => 'test title entry6',
'content' => 'This is my content /o/',
'language' => 'de',
'archived' => true,
'tags' => ['bar-tag'],
],
];
$entry1 = new Entry($this->getReference('admin-user'));
$entry1->setUrl('http://0.0.0.0/entry1');
$entry1->setReadingTime(11);
$entry1->setDomainName('domain.io');
$entry1->setMimetype('text/html');
$entry1->setTitle('test title entry1');
$entry1->setContent('This is my content /o/');
$entry1->setLanguage('en');
foreach ($entries as $reference => $item) {
$entry = new Entry($this->getReference($item['user']));
$entry->setUrl($item['url']);
$entry->setReadingTime($item['reading_time']);
$entry->setDomainName($item['domain']);
$entry->setMimetype($item['mime']);
$entry->setTitle($item['title']);
$entry->setContent($item['content']);
$entry->setLanguage($item['language']);
$entry1->addTag($this->getReference('foo-tag'));
$entry1->addTag($this->getReference('baz-tag'));
if (isset($item['tags'])) {
foreach ($item['tags'] as $tag) {
$entry->addTag($this->getReference($tag));
}
}
$manager->persist($entry1);
if (isset($item['origin'])) {
$entry->setOriginUrl($item['origin']);
}
$this->addReference('entry1', $entry1);
if (isset($item['starred'])) {
$entry->setStarred($item['starred']);
}
$entry2 = new Entry($this->getReference('admin-user'));
$entry2->setUrl('http://0.0.0.0/entry2');
$entry2->setReadingTime(1);
$entry2->setDomainName('domain.io');
$entry2->setMimetype('text/html');
$entry2->setTitle('test title entry2');
$entry2->setContent('This is my content /o/');
$entry2->setOriginUrl('ftp://oneftp.tld');
$entry2->setLanguage('fr');
if (isset($item['archived'])) {
$entry->setArchived($item['archived']);
}
$manager->persist($entry2);
if (isset($item['preview'])) {
$entry->setPreviewPicture($item['preview']);
}
$this->addReference('entry2', $entry2);
$manager->persist($entry);
$this->addReference($reference, $entry);
}
$entry3 = new Entry($this->getReference('bob-user'));
$entry3->setUrl('http://0.0.0.0/entry3');
$entry3->setReadingTime(1);
$entry3->setDomainName('domain.io');
$entry3->setMimetype('text/html');
$entry3->setTitle('test title entry3');
$entry3->setContent('This is my content /o/');
$entry3->setLanguage('en');
$entry3->addTag($this->getReference('foo-tag'));
$entry3->addTag($this->getReference('bar-tag'));
$manager->persist($entry3);
$this->addReference('entry3', $entry3);
$entry4 = new Entry($this->getReference('admin-user'));
$entry4->setUrl('http://0.0.0.0/entry4');
$entry4->setReadingTime(12);
$entry4->setDomainName('domain.io');
$entry4->setMimetype('text/html');
$entry4->setTitle('test title entry4');
$entry4->setContent('This is my content /o/');
$entry4->setLanguage('en');
$entry4->addTag($this->getReference('foo-tag'));
$entry4->addTag($this->getReference('bar-tag'));
$manager->persist($entry4);
$this->addReference('entry4', $entry4);
$entry5 = new Entry($this->getReference('admin-user'));
$entry5->setUrl('http://0.0.0.0/entry5');
$entry5->setReadingTime(12);
$entry5->setDomainName('domain.io');
$entry5->setMimetype('text/html');
$entry5->setTitle('test title entry5');
$entry5->setContent('This is my content /o/');
$entry5->setStarred(true);
$entry5->setLanguage('fr');
$entry5->setPreviewPicture('http://0.0.0.0/image.jpg');
$manager->persist($entry5);
$this->addReference('entry5', $entry5);
$entry6 = new Entry($this->getReference('admin-user'));
$entry6->setUrl('http://0.0.0.0/entry6');
$entry6->setReadingTime(12);
$entry6->setDomainName('domain.io');
$entry6->setMimetype('text/html');
$entry6->setTitle('test title entry6');
$entry6->setContent('This is my content /o/');
$entry6->setArchived(true);
$entry6->setLanguage('de');
$entry6->addTag($this->getReference('bar-tag'));
$manager->persist($entry6);
$this->addReference('entry6', $entry6);
$manager->flush();
}

View File

@ -5,38 +5,19 @@ namespace Wallabag\CoreBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Wallabag\CoreBundle\Entity\SiteCredential;
class LoadSiteCredentialData extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface
class LoadSiteCredentialData extends AbstractFixture implements OrderedFixtureInterface
{
/**
* @var ContainerInterface
*/
private $container;
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
/**
* {@inheritdoc}
*/
public function load(ObjectManager $manager)
{
$credential = new SiteCredential($this->getReference('admin-user'));
$credential->setHost('.super.com');
$credential->setUsername($this->container->get('wallabag_core.helper.crypto_proxy')->crypt('.super'));
$credential->setPassword($this->container->get('wallabag_core.helper.crypto_proxy')->crypt('bar'));
$manager->persist($credential);
$credential = new SiteCredential($this->getReference('admin-user'));
$credential->setHost('paywall.example.com');
$credential->setUsername($this->container->get('wallabag_core.helper.crypto_proxy')->crypt('paywall.example'));
$credential->setPassword($this->container->get('wallabag_core.helper.crypto_proxy')->crypt('bar'));
$credential->setHost('example.com');
$credential->setUsername('foo');
$credential->setPassword('bar');
$manager->persist($credential);

View File

@ -14,22 +14,33 @@ class LoadTagData extends AbstractFixture implements OrderedFixtureInterface
*/
public function load(ObjectManager $manager)
{
$tags = [
'foo-bar-tag' => 'foo bar', //tag used for EntryControllerTest
'bar-tag' => 'bar',
'baz-tag' => 'baz', // tag used for ExportControllerTest
'foo-tag' => 'foo',
'bob-tag' => 'bob', // tag used for TagRestControllerTest
];
$tag1 = new Tag();
$tag1->setLabel('foo bar');
foreach ($tags as $reference => $label) {
$tag = new Tag();
$tag->setLabel($label);
$manager->persist($tag1);
$manager->persist($tag);
$this->addReference('foo-bar-tag', $tag1);
$this->addReference($reference, $tag);
}
$tag2 = new Tag();
$tag2->setLabel('bar');
$manager->persist($tag2);
$this->addReference('bar-tag', $tag2);
$tag3 = new Tag();
$tag3->setLabel('baz');
$manager->persist($tag3);
$this->addReference('baz-tag', $tag3);
$tag4 = new Tag();
$tag4->setLabel('foo');
$manager->persist($tag4);
$this->addReference('foo-tag', $tag4);
$manager->flush();
}

View File

@ -108,7 +108,7 @@ class EntryFilterType extends AbstractType
->add('httpStatus', TextFilterType::class, [
'apply_filter' => function (QueryInterface $filterQuery, $field, $values) {
$value = $values['value'];
if (false === \array_key_exists($value, Response::$statusTexts)) {
if (false === array_key_exists($value, Response::$statusTexts)) {
return;
}

View File

@ -62,24 +62,11 @@ class GrabySiteConfigBuilder implements SiteConfigBuilder
$host = substr($host, 4);
}
if (!$this->currentUser) {
$this->logger->debug('Auth: no current user defined.');
return false;
$credentials = null;
if ($this->currentUser) {
$credentials = $this->credentialRepository->findOneByHostAndUser($host, $this->currentUser->getId());
}
$hosts = [$host];
// will try to see for a host without the first subdomain (fr.example.org & .example.org)
$split = explode('.', $host);
if (\count($split) > 1) {
// remove first subdomain
array_shift($split);
$hosts[] = '.' . implode('.', $split);
}
$credentials = $this->credentialRepository->findOneByHostsAndUser($hosts, $this->currentUser->getId());
if (null === $credentials) {
$this->logger->debug('Auth: no credentials available for host.', ['host' => $host]);

View File

@ -47,14 +47,12 @@ class ContentProxy
*/
public function updateEntry(Entry $entry, $url, array $content = [], $disableContentUpdate = false)
{
$this->graby->toggleImgNoReferrer(true);
if (!empty($content['html'])) {
$content['html'] = $this->graby->cleanupHtml($content['html'], $url);
}
if ((empty($content) || false === $this->validateContent($content)) && false === $disableContentUpdate) {
$fetchedContent = $this->graby->fetchContent($url);
$fetchedContent['title'] = $this->sanitizeContentTitle($fetchedContent['title'], $fetchedContent['content_type']);
// when content is imported, we have information in $content
// in case fetching content goes bad, we'll keep the imported information instead of overriding them
@ -67,13 +65,6 @@ class ContentProxy
// so we'll be able to refetch it in the future
$content['url'] = !empty($content['url']) ? $content['url'] : $url;
// In one case (at least in tests), url is empty here
// so we set it using $url provided in the updateEntry call.
// Not sure what are the other possible cases where this property is empty
if (empty($entry->getUrl()) && !empty($url)) {
$entry->setUrl($url);
}
$this->stockEntry($entry, $content);
}
@ -185,59 +176,6 @@ class ContentProxy
$entry->setTitle($path);
}
/**
* Try to sanitize the title of the fetched content from wrong character encodings and invalid UTF-8 character.
*
* @param $title
* @param $contentType
*
* @return string
*/
private function sanitizeContentTitle($title, $contentType)
{
if ('application/pdf' === $contentType) {
$title = $this->convertPdfEncodingToUTF8($title);
}
return $this->sanitizeUTF8Text($title);
}
/**
* If the title from the fetched content comes from a PDF, then its very possible that the character encoding is not
* UTF-8. This methods tries to identify the character encoding and translate the title to UTF-8.
*
* @param $title
*
* @return string (maybe contains invalid UTF-8 character)
*/
private function convertPdfEncodingToUTF8($title)
{
// first try UTF-8 because its easier to detect its present/absence
foreach (['UTF-8', 'UTF-16BE', 'WINDOWS-1252'] as $encoding) {
if (mb_check_encoding($title, $encoding)) {
return mb_convert_encoding($title, 'UTF-8', $encoding);
}
}
return $title;
}
/**
* Remove invalid UTF-8 characters from the given string.
*
* @param string $rawText
*
* @return string
*/
private function sanitizeUTF8Text($rawText)
{
if (mb_check_encoding($rawText, 'UTF-8')) {
return $rawText;
}
return iconv('UTF-8', 'UTF-8//IGNORE', $rawText);
}
/**
* Stock entry with fetched or imported content.
* Will fall back to OpenGraph data if available.
@ -247,7 +185,7 @@ class ContentProxy
*/
private function stockEntry(Entry $entry, array $content)
{
$this->updateOriginUrl($entry, $content['url']);
$entry->setUrl($content['url']);
$this->setEntryDomainName($entry);
@ -257,17 +195,18 @@ class ContentProxy
$entry->setTitle($content['open_graph']['og_title']);
}
if (empty($content['html'])) {
$content['html'] = $this->fetchingErrorMessage;
$html = $content['html'];
if (false === $html) {
$html = $this->fetchingErrorMessage;
if (!empty($content['open_graph']['og_description'])) {
$content['html'] .= '<p><i>But we found a short description: </i></p>';
$content['html'] .= $content['open_graph']['og_description'];
$html .= '<p><i>But we found a short description: </i></p>';
$html .= $content['open_graph']['og_description'];
}
}
$entry->setContent($content['html']);
$entry->setReadingTime(Utils::getReadingTime($content['html']));
$entry->setContent($html);
$entry->setReadingTime(Utils::getReadingTime($html));
if (!empty($content['status'])) {
$entry->setHttpStatus($content['status']);
@ -312,115 +251,6 @@ class ContentProxy
}
}
/**
* Update the origin_url field when a redirection occurs
* This field is set if it is empty and new url does not match ignore list.
*
* @param Entry $entry
* @param string $url
*/
private function updateOriginUrl(Entry $entry, $url)
{
if (empty($url) || $entry->getUrl() === $url) {
return false;
}
$parsed_entry_url = parse_url($entry->getUrl());
$parsed_content_url = parse_url($url);
/**
* The following part computes the list of part changes between two
* parse_url arrays.
*
* As array_diff_assoc only computes changes to go from the left array
* to the right one, we make two differents arrays to have both
* directions. We merge these two arrays and sort keys before passing
* the result to the switch.
*
* The resulting array gives us all changing parts between the two
* urls: scheme, host, path, query and/or fragment.
*/
$diff_ec = array_diff_assoc($parsed_entry_url, $parsed_content_url);
$diff_ce = array_diff_assoc($parsed_content_url, $parsed_entry_url);
$diff = array_merge($diff_ec, $diff_ce);
$diff_keys = array_keys($diff);
sort($diff_keys);
if ($this->ignoreUrl($entry->getUrl())) {
$entry->setUrl($url);
return false;
}
/**
* This switch case lets us apply different behaviors according to
* changing parts of urls.
*
* As $diff_keys is an array, we provide arrays as cases. ['path'] means
* 'only the path is different between the two urls' whereas
* ['fragment', 'query'] means 'only fragment and query string parts are
* different between the two urls'.
*
* Note that values in $diff_keys are sorted.
*/
switch ($diff_keys) {
case ['path']:
if (($parsed_entry_url['path'] . '/' === $parsed_content_url['path']) // diff is trailing slash, we only replace the url of the entry
|| ($url === urldecode($entry->getUrl()))) { // we update entry url if new url is a decoded version of it, see EntryRepository#findByUrlAndUserId
$entry->setUrl($url);
}
break;
case ['scheme']:
$entry->setUrl($url);
break;
case ['fragment']:
// noop
break;
default:
if (empty($entry->getOriginUrl())) {
$entry->setOriginUrl($entry->getUrl());
}
$entry->setUrl($url);
break;
}
}
/**
* Check entry url against an ignore list to replace with content url.
*
* XXX: move the ignore list in the database to let users handle it
*
* @param string $url url to test
*
* @return bool true if url matches ignore list otherwise false
*/
private function ignoreUrl($url)
{
$ignored_hosts = ['feedproxy.google.com', 'feeds.reuters.com'];
$ignored_patterns = ['https?://www\.lemonde\.fr/tiny.*'];
$parsed_url = parse_url($url);
$filtered = array_filter($ignored_hosts, function ($var) use ($parsed_url) {
return $var === $parsed_url['host'];
});
if ([] !== $filtered) {
return true;
}
$filtered = array_filter($ignored_patterns, function ($var) use ($url) {
return preg_match("`$var`i", $url);
});
if ([] !== $filtered) {
return true;
}
return false;
}
/**
* Validate that the given content has at least a title, an html and a url.
*

View File

@ -85,7 +85,7 @@ class EntriesExport
public function updateAuthor($method)
{
if ('entry' !== $method) {
$this->author = 'Various authors';
$this->author = $method . ' authors';
return $this;
}
@ -150,6 +150,8 @@ class EntriesExport
*/
$book->setTitle($this->title);
// Could also be the ISBN number, prefered for published books, or a UUID.
$book->setIdentifier($this->title, EPub::IDENTIFIER_URI);
// Not needed, but included for the example, Language is mandatory, but EPub defaults to "en". Use RFC3066 Language codes, such as "en", "da", "fr" etc.
$book->setLanguage($this->language);
$book->setDescription('Some articles saved on my wallabag');
@ -165,9 +167,12 @@ class EntriesExport
$book->addDublinCoreMetadata(DublinCore::CONTRIBUTOR, 'PHP');
$book->addDublinCoreMetadata(DublinCore::CONTRIBUTOR, 'wallabag');
$entryIds = [];
$entryCount = \count($this->entries);
$i = 0;
/*
* Front page
*/
if (file_exists($this->logoPath)) {
$book->setCoverImage('Cover.png', file_get_contents($this->logoPath), 'image/png');
}
/*
* Adding actual entries
@ -175,48 +180,21 @@ class EntriesExport
// set tags as subjects
foreach ($this->entries as $entry) {
++$i;
/*
* Front page
* Set if there's only one entry in the given set
*/
if (1 === $entryCount && null !== $entry->getPreviewPicture()) {
$book->setCoverImage($entry->getPreviewPicture());
}
foreach ($entry->getTags() as $tag) {
$book->setSubject($tag->getLabel());
}
$filename = sha1(sprintf('%s:%s', $entry->getUrl(), $entry->getTitle()));
$publishedBy = $entry->getPublishedBy();
$authors = $this->translator->trans('export.unknown');
if (!empty($publishedBy)) {
$authors = implode(',', $publishedBy);
}
// the reader in Kobo Devices doesn't likes special caracters
// in filenames, we limit to A-z/0-9
$filename = preg_replace('/[^A-Za-z0-9\-]/', '', $entry->getTitle());
$titlepage = $content_start .
'<h1>' . $entry->getTitle() . '</h1>' .
'<dl>' .
'<dt>' . $this->translator->trans('entry.view.published_by') . '</dt><dd>' . $authors . '</dd>' .
'<dt>' . $this->translator->trans('entry.metadata.reading_time') . '</dt><dd>' . $this->translator->trans('entry.metadata.reading_time_minutes_short', ['%readingTime%' => $entry->getReadingTime()]) . '</dd>' .
'<dt>' . $this->translator->trans('entry.metadata.added_on') . '</dt><dd>' . $entry->getCreatedAt()->format('Y-m-d') . '</dd>' .
'<dt>' . $this->translator->trans('entry.metadata.address') . '</dt><dd><a href="' . $entry->getUrl() . '">' . $entry->getUrl() . '</a></dd>' .
'</dl>' .
$bookEnd;
$book->addChapter("Entry {$i} of {$entryCount}", "{$filename}_cover.html", $titlepage, true, EPub::EXTERNAL_REF_ADD);
$titlepage = $content_start . '<h1>' . $entry->getTitle() . '</h1>' . $this->getExportInformation('PHPePub') . $bookEnd;
$book->addChapter('Title', 'Title.html', $titlepage, true, EPub::EXTERNAL_REF_ADD);
$chapter = $content_start . $entry->getContent() . $bookEnd;
$entryIds[] = $entry->getId();
$book->addChapter($entry->getTitle(), "{$filename}.html", $chapter, true, EPub::EXTERNAL_REF_ADD);
$book->addChapter($entry->getTitle(), htmlspecialchars($filename) . '.html', $chapter, true, EPub::EXTERNAL_REF_ADD);
}
$book->addChapter('Notices', 'Cover2.html', $content_start . $this->getExportInformation('PHPePub') . $bookEnd);
// Could also be the ISBN number, prefered for published books, or a UUID.
$hash = sha1(sprintf('%s:%s', $this->wallabagUrl, implode(',', $entryIds)));
$book->setIdentifier(sprintf('urn:wallabag:%s', $hash), EPub::IDENTIFIER_URI);
$book->buildTOC();
return Response::create(
$book->getBook(),
@ -224,7 +202,7 @@ class EntriesExport
[
'Content-Description' => 'File Transfer',
'Content-type' => 'application/epub+zip',
'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.epub"',
'Content-Disposition' => 'attachment; filename="' . $this->title . '.epub"',
'Content-Transfer-Encoding' => 'binary',
]
);
@ -266,6 +244,9 @@ class EntriesExport
}
$mobi->setContentProvider($content);
// the browser inside Kindle Devices doesn't likes special caracters either, we limit to A-z/0-9
$this->title = preg_replace('/[^A-Za-z0-9\-]/', '', $this->title);
return Response::create(
$mobi->toString(),
200,
@ -273,7 +254,7 @@ class EntriesExport
'Accept-Ranges' => 'bytes',
'Content-Description' => 'File Transfer',
'Content-type' => 'application/x-mobipocket-ebook',
'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.mobi"',
'Content-Disposition' => 'attachment; filename="' . $this->title . '.mobi"',
'Content-Transfer-Encoding' => 'binary',
]
);
@ -297,6 +278,14 @@ class EntriesExport
$pdf->SetSubject('Articles via wallabag');
$pdf->SetKeywords('wallabag');
/*
* Front page
*/
$pdf->AddPage();
$intro = '<h1>' . $this->title . '</h1>' . $this->getExportInformation('tcpdf');
$pdf->writeHTMLCell(0, 0, '', '', $intro, 0, 1, 0, true, '', true);
/*
* Adding actual entries
*/
@ -305,22 +294,6 @@ class EntriesExport
$pdf->SetKeywords($tag->getLabel());
}
$publishedBy = $entry->getPublishedBy();
$authors = $this->translator->trans('export.unknown');
if (!empty($publishedBy)) {
$authors = implode(',', $publishedBy);
}
$pdf->addPage();
$html = '<h1>' . $entry->getTitle() . '</h1>' .
'<dl>' .
'<dt>' . $this->translator->trans('entry.view.published_by') . '</dt><dd>' . $authors . '</dd>' .
'<dt>' . $this->translator->trans('entry.metadata.reading_time') . '</dt><dd>' . $this->translator->trans('entry.metadata.reading_time_minutes_short', ['%readingTime%' => $entry->getReadingTime()]) . '</dd>' .
'<dt>' . $this->translator->trans('entry.metadata.added_on') . '</dt><dd>' . $entry->getCreatedAt()->format('Y-m-d') . '</dd>' .
'<dt>' . $this->translator->trans('entry.metadata.address') . '</dt><dd><a href="' . $entry->getUrl() . '">' . $entry->getUrl() . '</a></dd>' .
'</dl>';
$pdf->writeHTMLCell(0, 0, '', '', $html, 0, 1, 0, true, '', true);
$pdf->AddPage();
$html = '<h1>' . $entry->getTitle() . '</h1>';
$html .= $entry->getContent();
@ -328,14 +301,6 @@ class EntriesExport
$pdf->writeHTMLCell(0, 0, '', '', $html, 0, 1, 0, true, '', true);
}
/*
* Last page
*/
$pdf->AddPage();
$html = $this->getExportInformation('tcpdf');
$pdf->writeHTMLCell(0, 0, '', '', $html, 0, 1, 0, true, '', true);
// set image scale factor
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
@ -345,7 +310,7 @@ class EntriesExport
[
'Content-Description' => 'File Transfer',
'Content-type' => 'application/pdf',
'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.pdf"',
'Content-Disposition' => 'attachment; filename="' . $this->title . '.pdf"',
'Content-Transfer-Encoding' => 'binary',
]
);
@ -391,7 +356,7 @@ class EntriesExport
200,
[
'Content-type' => 'application/csv',
'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.csv"',
'Content-Disposition' => 'attachment; filename="' . $this->title . '.csv"',
'Content-Transfer-Encoding' => 'UTF-8',
]
);
@ -409,7 +374,7 @@ class EntriesExport
200,
[
'Content-type' => 'application/json',
'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.json"',
'Content-Disposition' => 'attachment; filename="' . $this->title . '.json"',
'Content-Transfer-Encoding' => 'UTF-8',
]
);
@ -427,7 +392,7 @@ class EntriesExport
200,
[
'Content-type' => 'application/xml',
'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.xml"',
'Content-Disposition' => 'attachment; filename="' . $this->title . '.xml"',
'Content-Transfer-Encoding' => 'UTF-8',
]
);
@ -453,7 +418,7 @@ class EntriesExport
200,
[
'Content-type' => 'text/plain',
'Content-Disposition' => 'attachment; filename="' . $this->getSanitizedFilename() . '.txt"',
'Content-Disposition' => 'attachment; filename="' . $this->title . '.txt"',
'Content-Transfer-Encoding' => 'UTF-8',
]
);
@ -496,15 +461,4 @@ class EntriesExport
return str_replace('%IMAGE%', '', $info);
}
/**
* Return a sanitized version of the title by applying translit iconv
* and removing non alphanumeric characters, - and space.
*
* @return string Sanitized filename
*/
private function getSanitizedFilename()
{
return preg_replace('/[^A-Za-z0-9\- \']/', '', iconv('utf-8', 'us-ascii//TRANSLIT', $this->title));
}
}

View File

@ -23,7 +23,7 @@ class PreparePagerForEntries
* @param AdapterInterface $adapter
* @param User $user If user isn't logged in, we can force it (like for rss)
*
* @return Pagerfanta|null
* @return null|Pagerfanta
*/
public function prepare(AdapterInterface $adapter, User $user = null)
{

View File

@ -142,7 +142,7 @@ class EntryRepository extends EntityRepository
*
* @return Pagerfanta
*/
public function findEntries($userId, $isArchived = null, $isStarred = null, $isPublic = null, $sort = 'created', $order = 'asc', $since = 0, $tags = '')
public function findEntries($userId, $isArchived = null, $isStarred = null, $isPublic = null, $sort = 'created', $order = 'ASC', $since = 0, $tags = '')
{
$qb = $this->createQueryBuilder('e')
->leftJoin('e.tags', 't')
@ -185,10 +185,6 @@ class EntryRepository extends EntityRepository
}
}
if (!\in_array(strtolower($order), ['asc', 'desc'], true)) {
throw new \Exception('Order "' . $order . '" parameter is wrong, allowed: asc or desc');
}
if ('created' === $sort) {
$qb->orderBy('e.id', $order);
} elseif ('updated' === $sort) {

View File

@ -19,16 +19,16 @@ class SiteCredentialRepository extends \Doctrine\ORM\EntityRepository
/**
* Retrieve one username/password for the given host and userId.
*
* @param array $hosts An array of host to look for
* @param int $userId
* @param string $host
* @param int $userId
*
* @return array|null
* @return null|array
*/
public function findOneByHostsAndUser($hosts, $userId)
public function findOneByHostAndUser($host, $userId)
{
$res = $this->createQueryBuilder('s')
->select('s.username', 's.password')
->where('s.host IN (:hosts)')->setParameter('hosts', $hosts)
->where('s.host = :hostname')->setParameter('hostname', $host)
->andWhere('s.user = :userId')->setParameter('userId', $userId)
->setMaxResults(1)
->getQuery()

View File

@ -3,7 +3,6 @@
namespace Wallabag\CoreBundle\Repository;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\QueryBuilder;
use Wallabag\CoreBundle\Entity\Tag;
class TagRepository extends EntityRepository
@ -46,8 +45,12 @@ class TagRepository extends EntityRepository
*/
public function findAllTags($userId)
{
$ids = $this->getQueryBuilderByUser($userId)
$ids = $this->createQueryBuilder('t')
->select('t.id')
->leftJoin('t.entries', 'e')
->where('e.user = :userId')->setParameter('userId', $userId)
->groupBy('t.id')
->orderBy('t.slug')
->getQuery()
->getArrayResult();
@ -68,30 +71,18 @@ class TagRepository extends EntityRepository
*/
public function findAllFlatTagsWithNbEntries($userId)
{
return $this->getQueryBuilderByUser($userId)
return $this->createQueryBuilder('t')
->select('t.id, t.label, t.slug, count(e.id) as nbEntries')
->distinct(true)
->leftJoin('t.entries', 'e')
->where('e.user = :userId')
->groupBy('t.id')
->orderBy('t.slug')
->setParameter('userId', $userId)
->getQuery()
->getArrayResult();
}
public function findByLabelsAndUser($labels, $userId)
{
$qb = $this->getQueryBuilderByUser($userId)
->select('t.id');
$ids = $qb->andWhere($qb->expr()->in('t.label', $labels))
->getQuery()
->getArrayResult();
$tags = [];
foreach ($ids as $id) {
$tags[] = $this->find($id);
}
return $tags;
}
/**
* Used only in test case to get a tag for our entry.
*
@ -110,9 +101,13 @@ class TagRepository extends EntityRepository
public function findForArchivedArticlesByUser($userId)
{
$ids = $this->getQueryBuilderByUser($userId)
$ids = $this->createQueryBuilder('t')
->select('t.id')
->leftJoin('t.entries', 'e')
->where('e.user = :userId')->setParameter('userId', $userId)
->andWhere('e.isArchived = true')
->groupBy('t.id')
->orderBy('t.slug')
->getQuery()
->getArrayResult();
@ -123,20 +118,4 @@ class TagRepository extends EntityRepository
return $tags;
}
/**
* Retrieve a sorted list of tags used by a user.
*
* @param int $userId
*
* @return QueryBuilder
*/
private function getQueryBuilderByUser($userId)
{
return $this->createQueryBuilder('t')
->leftJoin('t.entries', 'e')
->where('e.user = :userId')->setParameter('userId', $userId)
->groupBy('t.id')
->orderBy('t.slug');
}
}

View File

@ -157,8 +157,8 @@ config:
# not_equal_to: 'Not equal to...'
# or: 'One rule OR another'
# and: 'One rule AND another'
# matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
# notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
# matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
# notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
# default_title: 'Title of the entry'
@ -253,11 +253,6 @@ entry:
confirm:
# delete: "Are you sure you want to remove that article?"
# delete_tag: "Are you sure you want to remove that tag from that article?"
metadata:
# reading_time: "Estimated reading time"
# reading_time_minutes_short: "%readingTime% min"
# address: "Address"
# added_on: "Added on"
about:
page_title: 'Om'
@ -407,7 +402,6 @@ tag:
# export:
# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>'
# unknown: 'Unknown'
import:
# page_title: 'Import'
@ -550,7 +544,7 @@ site_credential:
# create_new_one: Create a new credential
# form:
# username_label: 'Username'
# host_label: 'Host (subdomain.example.org, .example.org, etc.)'
# host_label: 'Host'
# password_label: 'Password'
# save: Save
# delete: Delete

View File

@ -253,11 +253,6 @@ entry:
confirm:
delete: 'Bist du sicher, dass du diesen Artikel löschen möchtest?'
delete_tag: 'Bist du sicher, dass du diesen Tag vom Artikel entfernen möchtest?'
metadata:
# reading_time: "Estimated reading time"
# reading_time_minutes_short: "%readingTime% min"
# address: "Address"
# added_on: "Added on"
about:
page_title: 'Über'
@ -407,7 +402,6 @@ tag:
export:
footer_template: '<div style="text-align:center;"><p>Generiert von wallabag mit Hilfe von %method%</p><p>Bitte öffne <a href="https://github.com/wallabag/wallabag/issues">ein Ticket</a> wenn du ein Problem mit der Darstellung von diesem E-Book auf deinem Gerät hast.</p></div>'
# unknown: 'Unknown'
import:
page_title: 'Importieren'
@ -550,7 +544,7 @@ site_credential:
create_new_one: 'Einen neuen Seitenzugang anlegen'
form:
username_label: 'Benutzername'
host_label: 'Host (subdomain.example.org, .example.org, etc.)'
host_label: 'Host'
password_label: 'Passwort'
save: 'Speichern'
delete: 'Löschen'

View File

@ -72,9 +72,9 @@ config:
300_word: 'I read ~300 words per minute'
400_word: 'I read ~400 words per minute'
action_mark_as_read:
label: 'What to do after removing, starring or marking as read an article?'
redirect_homepage: 'Go to the homepage'
redirect_current_page: 'Stay on the current page'
label: 'Where do you want to be redirected to after marking an article as read?'
redirect_homepage: 'To the homepage'
redirect_current_page: 'To the current page'
pocket_consumer_key_label: Consumer key for Pocket to import contents
android_configuration: Configure your Android application
android_instruction: "Touch here to prefill your Android application"
@ -157,8 +157,8 @@ config:
not_equal_to: 'Not equal to...'
or: 'One rule OR another'
and: 'One rule AND another'
matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
default_title: 'Title of the entry'
@ -253,11 +253,6 @@ entry:
confirm:
delete: "Are you sure you want to remove that article?"
delete_tag: "Are you sure you want to remove that tag from that article?"
metadata:
reading_time: "Estimated reading time"
reading_time_minutes_short: "%readingTime% min"
address: "Address"
added_on: "Added on"
about:
page_title: 'About'
@ -407,7 +402,6 @@ tag:
export:
footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>'
unknown: 'Unknown'
import:
page_title: 'Import'
@ -550,7 +544,7 @@ site_credential:
create_new_one: Create a new credential
form:
username_label: 'Username'
host_label: 'Host (subdomain.example.org, .example.org, etc.)'
host_label: 'Host'
password_label: 'Password'
save: Save
delete: Delete

View File

@ -158,7 +158,7 @@ config:
or: 'Una regla U otra'
and: 'Una regla Y la otra'
matches: 'Prueba si un <i>sujeto</i> corresponde a una <i>búsqueda</i> (insensible a mayusculas).<br />Ejemplo : <code>title matches "fútbol"</code>'
# notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
# notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
default_title: 'Título del artículo'
@ -253,11 +253,6 @@ entry:
confirm:
# delete: "Are you sure you want to remove that article?"
# delete_tag: "Are you sure you want to remove that tag from that article?"
metadata:
# reading_time: "Estimated reading time"
# reading_time_minutes_short: "%readingTime% min"
# address: "Address"
# added_on: "Added on"
about:
page_title: 'Acerca de'
@ -407,7 +402,6 @@ tag:
# export:
# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>'
# unknown: 'Unknown'
import:
page_title: 'Importar'
@ -550,7 +544,7 @@ site_credential:
# create_new_one: Create a new credential
# form:
# username_label: 'Username'
# host_label: 'Host (subdomain.example.org, .example.org, etc.)'
# host_label: 'Host'
# password_label: 'Password'
# save: Save
# delete: Delete

View File

@ -157,8 +157,8 @@ config:
# not_equal_to: 'Not equal to...'
# or: 'One rule OR another'
# and: 'One rule AND another'
# matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
# notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
# matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
# notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
# default_title: 'Title of the entry'
@ -253,11 +253,6 @@ entry:
confirm:
# delete: "Are you sure you want to remove that article?"
# delete_tag: "Are you sure you want to remove that tag from that article?"
metadata:
# reading_time: "Estimated reading time"
# reading_time_minutes_short: "%readingTime% min"
# address: "Address"
# added_on: "Added on"
about:
page_title: 'درباره'
@ -407,7 +402,6 @@ tag:
# export:
# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>'
# unknown: 'Unknown'
import:
page_title: 'درون‌ریزی'
@ -550,7 +544,7 @@ site_credential:
# create_new_one: Create a new credential
# form:
# username_label: 'Username'
# host_label: 'Host (subdomain.example.org, .example.org, etc.)'
# host_label: 'Host'
# password_label: 'Password'
# save: Save
# delete: Delete

View File

@ -72,9 +72,9 @@ config:
300_word: "Je lis environ 300 mots par minute"
400_word: "Je lis environ 400 mots par minute"
action_mark_as_read:
label: "Que faire lorsqu'un article est supprimé, marqué comme lu ou marqué comme favoris ?"
redirect_homepage: "Retourner à la page daccueil"
redirect_current_page: "Rester sur la page actuelle"
label: "Où souhaitez-vous être redirigé après avoir marqué un article comme lu ?"
redirect_homepage: "À la page daccueil"
redirect_current_page: "À la page courante"
pocket_consumer_key_label: "Clé dauthentification Pocket pour importer les données"
android_configuration: "Configurez votre application Android"
android_instruction: "Appuyez ici pour préremplir votre application Android"
@ -253,11 +253,6 @@ entry:
confirm:
delete: "Voulez-vous vraiment supprimer cet article ?"
delete_tag: "Voulez-vous vraiment supprimer ce tag de cet article ?"
metadata:
reading_time: "Durée de lecture estimée"
reading_time_minutes_short: "%readingTime% min"
address: "Adresse"
added_on: "Ajouté le"
about:
page_title: "À propos"
@ -407,7 +402,6 @@ tag:
export:
footer_template: '<div style="text-align:center;"><p>Généré par wallabag with %method%</p><p>Merci d''ouvrir <a href="https://github.com/wallabag/wallabag/issues">un ticket</a> si vous rencontrez des soucis d''affichage avec ce document sur votre support.</p></div>'
unknown: 'Inconnu'
import:
page_title: "Importer"
@ -550,7 +544,7 @@ site_credential:
create_new_one: Créer un nouvel accès à un site
form:
username_label: 'Identifiant'
host_label: 'Domaine (subdomain.example.org, .example.org, etc.)'
host_label: 'Domaine'
password_label: 'Mot de passe'
save: "Sauvegarder"
delete: "Supprimer"

View File

@ -158,7 +158,7 @@ config:
or: "Una regola O un'altra"
and: "Una regola E un'altra"
matches: 'Verifica che un <i>oggetto</i> risulti in una <i>ricerca</i> (case-insensitive).<br />Esempio: <code>titolo contiene "football"</code>'
# notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
# notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
default_title: "Titolo del contenuto"
@ -253,11 +253,6 @@ entry:
confirm:
delete: "Vuoi veramente rimuovere quell'articolo?"
delete_tag: "Vuoi veramente rimuovere quell'etichetta da quell'articolo?"
metadata:
# reading_time: "Estimated reading time"
# reading_time_minutes_short: "%readingTime% min"
# address: "Address"
# added_on: "Added on"
about:
page_title: 'A proposito'
@ -407,7 +402,6 @@ tag:
# export:
# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>'
# unknown: 'Unknown'
import:
page_title: 'Importa'
@ -550,7 +544,7 @@ site_credential:
# create_new_one: Create a new credential
# form:
# username_label: 'Username'
# host_label: 'Host (subdomain.example.org, .example.org, etc.)'
# host_label: 'Host'
# password_label: 'Password'
# save: Save
# delete: Delete

View File

@ -253,11 +253,6 @@ entry:
confirm:
delete: "Sètz segur de voler suprimir aqueste article?"
delete_tag: "Sètz segur de voler levar aquesta etiqueta de l'article?"
metadata:
# reading_time: "Estimated reading time"
# reading_time_minutes_short: "%readingTime% min"
# address: "Address"
# added_on: "Added on"
about:
page_title: 'A prepaus'
@ -407,7 +402,6 @@ tag:
export:
footer_template: '<div style="text-align:center;"><p>Produch per wallabag amb %method%</p><p>Mercés de dobrir <a href="https://github.com/wallabag/wallabag/issues">una sollicitacion</a> savètz de problèmas amb lafichatge daqueste E-Book sus vòstre periferic.</p></div>'
# unknown: 'Unknown'
import:
page_title: 'Importar'
@ -550,7 +544,7 @@ site_credential:
create_new_one: Crear un novèl identificant
form:
username_label: "Nom d'utilizaire"
host_label: 'Òste (subdomain.example.org, .example.org, etc.)'
host_label: 'Òste'
password_label: 'Senhal'
save: 'Enregistrar'
delete: 'Suprimir'

View File

@ -253,11 +253,6 @@ entry:
confirm:
delete: "Czy jesteś pewien, że chcesz usunąć ten artykuł?"
delete_tag: "Czy jesteś pewien, że chcesz usunąć ten tag, z tego artykułu?"
metadata:
# reading_time: "Estimated reading time"
# reading_time_minutes_short: "%readingTime% min"
# address: "Address"
# added_on: "Added on"
about:
page_title: 'O nas'
@ -406,8 +401,7 @@ tag:
placeholder: 'Możesz dodać kilka tagów, oddzielając je przecinkami.'
export:
footer_template: '<div style="text-align:center;"><p>Stworzone przez wallabag z %method%</p><p>Proszę zgłoś <a href="https://github.com/wallabag/wallabag/issues">sprawę</a>, jeżeli masz problem z wyświetleniem tego e-booka na swoim urządzeniu.</p></div>'
# unknown: 'Unknown'
footer_template: '<div style="text-align:center;"><p>Stworzone przez wallabag z %method%</p><p>Proszę zgłoś <a href="https://github.com/wallabag/wallabag/issues">sprawę</a>, jeżeli masz problem z wyświetleniem tego e-booka na swoim urządzeniu.</p></div>'
import:
page_title: 'Import'
@ -550,7 +544,7 @@ site_credential:
create_new_one: Stwórz nowe poświadczenie
form:
username_label: 'Nazwa użytkownika'
host_label: 'Host (subdomain.example.org, .example.org, etc.)'
host_label: 'Host'
password_label: 'Hasło'
save: Zapisz
delete: Usuń

View File

@ -158,7 +158,7 @@ config:
or: 'Uma regra OU outra'
and: 'Uma regra E outra'
matches: 'Testa que um <i>assunto</i> corresponde a uma <i>pesquisa</i> (maiúscula ou minúscula).<br />Exemplo: <code>título corresponde a "futebol"</code>'
# notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
# notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
default_title: 'Título da entrada'
@ -253,11 +253,6 @@ entry:
confirm:
# delete: "Are you sure you want to remove that article?"
# delete_tag: "Are you sure you want to remove that tag from that article?"
metadata:
# reading_time: "Estimated reading time"
# reading_time_minutes_short: "%readingTime% min"
# address: "Address"
# added_on: "Added on"
about:
page_title: 'Sobre'
@ -407,7 +402,6 @@ tag:
# export:
# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>'
# unknown: 'Unknown'
import:
page_title: 'Importar'
@ -550,7 +544,7 @@ site_credential:
# create_new_one: Create a new credential
form:
# username_label: 'Username'
# host_label: 'Host (subdomain.example.org, .example.org, etc.)'
# host_label: 'Host'
# password_label: 'Password'
save: 'Salvar'
delete: 'Apagar'

View File

@ -157,8 +157,8 @@ config:
# not_equal_to: 'Not equal to...'
# or: 'One rule OR another'
# and: 'One rule AND another'
# matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
# notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
# matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
# notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
# default_title: 'Title of the entry'
@ -253,11 +253,6 @@ entry:
confirm:
# delete: "Are you sure you want to remove that article?"
# delete_tag: "Are you sure you want to remove that tag from that article?"
metadata:
# reading_time: "Estimated reading time"
# reading_time_minutes_short: "%readingTime% min"
# address: "Address"
# added_on: "Added on"
about:
page_title: 'Despre'
@ -407,7 +402,6 @@ tag:
# export:
# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>'
# unknown: 'Unknown'
import:
# page_title: 'Import'
@ -550,7 +544,7 @@ site_credential:
# create_new_one: Create a new credential
# form:
# username_label: 'Username'
# host_label: 'Host (subdomain.example.org, .example.org, etc.)'
# host_label: 'Host'
# password_label: 'Password'
# save: Save
# delete: Delete

View File

@ -241,11 +241,6 @@ entry:
save_label: 'Сохранить'
public:
shared_by_wallabag: "Запись была опубликована <a href='%wallabag_instance%'>wallabag</a>"
metadata:
# reading_time: "Estimated reading time"
# reading_time_minutes_short: "%readingTime% min"
# address: "Address"
# added_on: "Added on"
about:
page_title: 'О'
@ -393,10 +388,6 @@ tag:
add: 'Добавить'
placeholder: 'Вы можете добавить несколько тегов, разделенных запятой.'
# export:
# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>'
# unknown: 'Unknown'
import:
page_title: 'Импорт'
page_description: 'Добро пожаловать в импортер wallabag. Выберите сервис, из которого вы хотите перенести данные.'

View File

@ -251,11 +251,6 @@ entry:
confirm:
delete: "คุณแน่ใจหรือไม่ว่าคุณต้องการลบบทความนี้?"
delete_tag: "คุณแน่ใจหรือไม่ว่าคุณต้องการลบแท็กจากบทความนี้?"
metadata:
# reading_time: "Estimated reading time"
# reading_time_minutes_short: "%readingTime% min"
# address: "Address"
# added_on: "Added on"
about:
page_title: 'เกี่ยวกับ'
@ -405,7 +400,6 @@ tag:
export:
footer_template: '<div style="text-align:center;"><p>ผลิตโดย wallabag กับ %method%</p><p>ให้ทำการเปิด <a href="https://github.com/wallabag/wallabag/issues">ฉบับนี้</a> ถ้าคุณมีข้อบกพร่องif you have trouble with the display of this E-Book on your device.</p></div>'
# unknown: 'Unknown'
import:
page_title: 'นำข้อมูลเช้า'
@ -548,7 +542,7 @@ site_credential:
create_new_one: สร้างข้อมูลส่วนตัวใหม่
form:
username_label: 'ชื่อผู้ใช้'
host_label: 'โฮส (subdomain.example.org, .example.org, etc.)'
host_label: 'โฮส'
password_label: 'รหัสผ่าน'
save: บันทึก
delete: ลบ

View File

@ -157,8 +157,8 @@ config:
not_equal_to: 'Eşit değildir…'
or: 'Bir kural veya birbaşkası'
and: 'Bir kural ve diğeri'
# matches: 'Tests that a <i>subject</i> matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
# notmatches: 'Tests that a <i>subject</i> doesn''t match match a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
# matches: 'Tests that a <i>subject</i> is matches a <i>search</i> (case-insensitive).<br />Example: <code>title matches "football"</code>'
# notmatches: 'Tests that a <i>subject</i> is not matches a <i>search</i> (case-insensitive).<br />Example: <code>title notmatches "football"</code>'
entry:
default_title: 'Makalenin başlığı'
@ -251,11 +251,6 @@ entry:
confirm:
# delete: "Are you sure you want to remove that article?"
# delete_tag: "Are you sure you want to remove that tag from that article?"
metadata:
# reading_time: "Estimated reading time"
# reading_time_minutes_short: "%readingTime% min"
# address: "Address"
# added_on: "Added on"
about:
page_title: 'Hakkımızda'
@ -405,7 +400,6 @@ tag:
# export:
# footer_template: '<div style="text-align:center;"><p>Produced by wallabag with %method%</p><p>Please open <a href="https://github.com/wallabag/wallabag/issues">an issue</a> if you have trouble with the display of this E-Book on your device.</p></div>'
# unknown: 'Unknown'
import:
page_title: 'İçe Aktar'

View File

@ -8,7 +8,6 @@
{% block head %}
<meta name="viewport" content="initial-scale=1.0">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="referrer" content="strict-origin-when-cross-origin">
<!--[if IE]>
<meta http-equiv="X-UA-Compatible" content="IE=10">
<![endif]-->
@ -39,8 +38,6 @@
<link rel="shortcut icon" type="image/x-icon" href="{{ asset('wallassets/themes/_global/img/appicon/favicon.ico') }}">
<link rel="manifest" href="{{ asset('manifest.json') }}">
{% block css %}
{% endblock %}
{% block scripts %}
@ -72,7 +69,7 @@
{% block footer %}{% endblock %}
{% if craue_setting('piwik_enabled') %}
{{ piwik(craue_setting('piwik_host'), craue_setting('piwik_site_id')) }}
{{ piwik(craue_setting('piwik_host')|e('html_attr'), craue_setting('piwik_site_id')|e('html_attr')) }}
{% endif %}
</body>
</html>

View File

@ -57,7 +57,7 @@
</div>
<ul class="tools links">
<li><a href="{{ entry.url|e }}" target="_blank" rel="noopener" title="{{ 'entry.list.original_article'|trans }} : {{ entry.title|e }}"><span>{{ entry.domainName|removeWww }}</span></a></li>
<li><a href="{{ entry.url|e }}" target="_blank" title="{{ 'entry.list.original_article'|trans }} : {{ entry.title|e }}"><span>{{ entry.domainName|removeWww }}</span></a></li>
<li><a title="{{ 'entry.list.toogle_as_read'|trans }}" class="tool icon {% if entry.isArchived == 0 %}archive-off{% else %}archive{% endif %}" href="{{ path('archive_entry', { 'id': entry.id }) }}"><i class="material-icons md-24 vertical-align-middle">check</i><span>{{ 'entry.list.toogle_as_read'|trans }}</span></a></li>
<li><a title="{{ 'entry.list.toogle_as_star'|trans }}" class="tool icon {% if entry.isStarred == 0 %}fav-off{% else %}fav{% endif %}" href="{{ path('star_entry', { 'id': entry.id }) }}"><i class="material-icons md-24 vertical-align-middle">star_rate</i><span>{{ 'entry.list.toogle_as_star'|trans }}</span></a></li>
<li><a title="{{ 'entry.list.delete'|trans }}" class="tool icon" onclick="return confirm('{{ 'entry.confirm.delete'|trans|escape('js') }}')" href="{{ path('delete_entry', { 'id': entry.id }) }}"><i class="material-icons md-24 vertical-align-middle">delete</i><span>{{ 'entry.list.delete'|trans }}</span></a></li>
@ -99,8 +99,8 @@
{% if craue_setting('export_epub') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'epub', 'tag' : currentTag }) }}">EPUB</a></li>{% endif %}
{% if craue_setting('export_mobi') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'mobi', 'tag' : currentTag }) }}">MOBI</a></li>{% endif %}
{% if craue_setting('export_pdf') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'pdf', 'tag' : currentTag }) }}">PDF</a></li>{% endif %}
{% if craue_setting('export_json') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'json', 'tag' : currentTag }) }}">JSON</a></li>{% endif %}
{% if craue_setting('export_csv') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'csv', 'tag' : currentTag }) }}">CSV</a></li>{% endif %}
{% if craue_setting('export_csv') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'json', 'tag' : currentTag }) }}">JSON</a></li>{% endif %}
{% if craue_setting('export_json') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'csv', 'tag' : currentTag }) }}">CSV</a></li>{% endif %}
{% if craue_setting('export_txt') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'txt', 'tag' : currentTag }) }}">TXT</a></li>{% endif %}
{% if craue_setting('export_xml') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'xml', 'tag' : currentTag }) }}">XML</a></li>{% endif %}
</ul>

View File

@ -11,7 +11,7 @@
<div id="article_toolbar">
<ul class="links">
<li class="topPosF"><a href="#top" title="{{ 'entry.view.left_menu.back_to_top'|trans }}" class="tool top icon icon-arrow-up-thick"><span>{{ 'entry.view.left_menu.set_as_read'|trans }}</span></a></li>
<li><a href="{{ entry.url|e }}" target="_blank" rel="noopener" title="{{ 'entry.view.original_article'|trans }} : {{ entry.title|e }}" class="tool link icon icon-link original"><span>{{ entry.domainName|removeWww }}</span></a></li>
<li><a href="{{ entry.url|e }}" target="_blank" title="{{ 'entry.view.original_article'|trans }} : {{ entry.title|e }}" class="tool link icon icon-link original"><span>{{ entry.domainName|removeWww }}</span></a></li>
<li><a title="{{ 'entry.view.left_menu.re_fetch_content'|trans }}" class="tool icon icon-reload" href="{{ path('reload_entry', { 'id': entry.id }) }}"><span>{{ 'entry.view.left_menu.re_fetch_content'|trans }}</span></a></li>
{% set markAsReadLabel = 'entry.view.left_menu.set_as_unread' %}
@ -27,18 +27,18 @@
<li><a href="{{ path('share', {'id': entry.id }) }}" target="_blank" class="tool icon icon-eye" title="{{ 'entry.view.left_menu.public_link'|trans }}"><span>{{ 'entry.view.left_menu.public_link'|trans }}</span></a></li>
<li><a href="{{ path('delete_share', {'id': entry.id }) }}" class="tool icon icon-no-eye" title="{{ 'entry.view.left_menu.delete_public_link'|trans }}"><span>{{ 'entry.view.left_menu.delete_public_link'|trans }}</span></a></li>
{% endif %}
{% if craue_setting('share_twitter') %}<li><a href="https://twitter.com/home?status={{entry.title|url_encode}}%20{{ entry.url|url_encode }}%20via%20@wallabagapp" target="_blank" rel="noopener" class="tool twitter icon icon-twitter" title="Tweet"><span>Tweet</span></a></li>{% endif %}
{% if craue_setting('share_twitter') %}<li><a href="https://twitter.com/home?status={{entry.title|url_encode}}%20{{ entry.url|url_encode }}%20via%20@wallabagapp" target="_blank" class="tool twitter icon icon-twitter" title="Tweet"><span>Tweet</span></a></li>{% endif %}
{% if craue_setting('share_mail') %}<li><a href="mailto:?subject={{ entry.title|url_encode }}&amp;body={{ entry.url|url_encode }}%20via%20@wallabagapp" class="tool email icon icon-mail" title="Email"><span>Email</span></a></li>{% endif %}
{% if craue_setting('share_shaarli') %}<li><a href="{{ craue_setting('shaarli_url') }}/index.php?post={{ entry.url|url_encode }}&amp;title={{ entry.title|url_encode }}&amp;tags={{ entry.tags|join(',')|url_encode }}{% if craue_setting('shaarli_share_origin_url') %}&amp;original_url={{ entry.originUrl|url_encode }}{% endif %}" target="_blank" rel="noopener" class="tool icon-image icon-image--shaarli" title="shaarli"><span>shaarli</span></a></li>{% endif %}
{% if craue_setting('share_scuttle') %}<li><a href="{{ craue_setting('scuttle_url') }}/bookmarks.php?action=add&amp;address={{ entry.url|url_encode }}&amp;title={{ entry.title|url_encode }}&amp;tags={{ entry.tags|join(',')|url_encode }}" target="_blank" rel="noopener" class="tool icon-image icon-image--scuttle" title="scuttle"><span>scuttle</span></a></li>{% endif %}
{% if craue_setting('share_diaspora') %}<li><a href="{{ craue_setting('diaspora_url') }}/bookmarklet?url={{ entry.url|url_encode }}&title={{ entry.title|url_encode }}&notes=&v=1&noui=1&jump=doclose" target="_blank" rel="noopener" class="tool diaspora icon-image icon-image--diaspora" title="diaspora"><span>diaspora</span></a></li>{% endif %}
{% if craue_setting('share_unmark') %}<li><a href="{{ craue_setting('unmark_url') }}/mark/add?url={{ entry.url|url_encode }}&amp;title={{entry.title|url_encode}}&amp;v=6" target="_blank" rel="noopener" class="tool unmark icon-image icon-image--unmark" title="unmark"><span>unmark.it</span></a></li>{% endif %}
{% if craue_setting('carrot') %}<li><a href="https://secure.carrot.org/GiveAndGetBack.do?url={{ entry.url|url_encode }}&title={{ entry.title|url_encode }}" class="tool carrot icon-image icon-image--carrot" target="_blank" rel="noopener" title="carrot"><span>Carrot</span></a></li>{% endif %}
{% if craue_setting('share_shaarli') %}<li><a href="{{ craue_setting('shaarli_url') }}/index.php?post={{ entry.url|url_encode }}&amp;title={{ entry.title|url_encode }}&amp;tags={{ entry.tags|join(',')|url_encode }}{% if craue_setting('shaarli_share_origin_url') %}&amp;original_url={{ entry.originUrl|url_encode }}{% endif %}" target="_blank" class="tool icon-image icon-image--shaarli" title="shaarli"><span>shaarli</span></a></li>{% endif %}
{% if craue_setting('share_scuttle') %}<li><a href="{{ craue_setting('scuttle_url') }}/bookmarks.php?action=add&amp;address={{ entry.url|url_encode }}&amp;title={{ entry.title|url_encode }}&amp;tags={{ entry.tags|join(',')|url_encode }}" target="_blank" class="tool icon-image icon-image--scuttle" title="scuttle"><span>scuttle</span></a></li>{% endif %}
{% if craue_setting('share_diaspora') %}<li><a href="{{ craue_setting('diaspora_url') }}/bookmarklet?url={{ entry.url|url_encode }}&title={{ entry.title|url_encode }}&notes=&v=1&noui=1&jump=doclose" target="_blank" class="tool diaspora icon-image icon-image--diaspora" title="diaspora"><span>diaspora</span></a></li>{% endif %}
{% if craue_setting('share_unmark') %}<li><a href="{{ craue_setting('unmark_url') }}/mark/add?url={{ entry.url|url_encode }}&amp;title={{entry.title|url_encode}}&amp;v=6" target="_blank" class="tool unmark icon-image icon-image--unmark" title="unmark"><span>unmark.it</span></a></li>{% endif %}
{% if craue_setting('carrot') %}<li><a href="https://secure.carrot.org/GiveAndGetBack.do?url={{ entry.url|url_encode }}&title={{ entry.title|url_encode }}" class="tool carrot icon-image icon-image--carrot" target="_blank" title="carrot"><span>Carrot</span></a></li>{% endif %}
{% if craue_setting('show_printlink') %}<li><a title="{{ 'entry.view.left_menu.print'|trans }}" class="tool icon icon-print" href="javascript: window.print();"><span>{{ 'entry.view.left_menu.print'|trans }}</span></a></li>{% endif %}
{% if craue_setting('export_epub') %}<li><a href="{{ path('export_entry', { 'id': entry.id, 'format': 'epub' }) }}" title="Generate ePub file">EPUB</a></li>{% endif %}
{% if craue_setting('export_mobi') %}<li><a href="{{ path('export_entry', { 'id': entry.id, 'format': 'mobi' }) }}" title="Generate Mobi file">MOBI</a></li>{% endif %}
{% if craue_setting('export_pdf') %}<li><a href="{{ path('export_entry', { 'id': entry.id, 'format': 'pdf' }) }}" title="Generate PDF file">PDF</a></li>{% endif %}
<li><a href="mailto:siteconfig@wallabag.org?subject=Wrong%20display%20in%20wallabag&amp;body={{ entry.url|url_encode }}" title="{{ 'entry.view.left_menu.problem.label'|trans }}" class="tool bad-display icon icon-delete"><span>{{ 'entry.view.left_menu.problem.label'|trans }}</span></a></li>
<li><a href="mailto:hello@wallabag.org?subject=Wrong%20display%20in%20wallabag&amp;body={{ entry.url|url_encode }}" title="{{ 'entry.view.left_menu.problem.label'|trans }}" class="tool bad-display icon icon-delete"><span>{{ 'entry.view.left_menu.problem.label'|trans }}</span></a></li>
</ul>
</div>
@ -74,7 +74,7 @@
{% if entry.originUrl is not empty %}
<i class="material-icons" title="{{ 'entry.view.provided_by'|trans }}">launch</i>
<a href="{{ entry.originUrl|e }}" target="_blank" rel="noopener" class="tool">
<a href="{{ entry.originUrl|e }}" target="_blank" class="tool">
{{ entry.originUrl|striptags|removeSchemeAndWww|truncate(32) }}
</a>
{% endif %}
@ -96,6 +96,9 @@
</div>
</aside>
</div>
{% if entry.previewPicture is not null %}
<div><img class="preview" src="{{ entry.previewPicture }}" alt="{{ entry.title|e|raw }}" /></div>
{% endif %}
<article>
{{ entry.content | raw }}
</article>

View File

@ -27,8 +27,11 @@
<body>
<header class="block">
<h1>{{ entry.title|e|raw }}</h1>
<a href="{{ entry.url|e }}" target="_blank" rel="noopener" title="{{ 'entry.view.original_article'|trans }} : {{ entry.title|e|raw }}" class="tool">{{ entry.domainName|removeWww }}</a>
<a href="{{ entry.url|e }}" target="_blank" title="{{ 'entry.view.original_article'|trans }} : {{ entry.title|e|raw }}" class="tool">{{ entry.domainName|removeWww }}</a>
<p class="shared-by">{{ "entry.public.shared_by_wallabag"|trans({'%wallabag_instance%': url('homepage'), '%username%': entry.user.username})|raw }}.</p>
{% if entry.previewPicture is not null %}
<img class="preview" src="{{ entry.previewPicture }}" alt="{{ entry.title|striptags|e('html_attr') }}" />
{% endif %}
</header>
<article class="block">
{{ entry.content | raw }}

View File

@ -28,18 +28,18 @@
<div class="col s12">
<h5>{{ 'howto.top_menu.browser_addons'|trans }}</h5>
<ul>
<li><a href="{{ addonsUrl.firefox }}" target="_blank" rel="noopener">{{ 'howto.browser_addons.firefox'|trans }}</a></li>
<li><a href="{{ addonsUrl.chrome }}" target="_blank" rel="noopener">{{ 'howto.browser_addons.chrome'|trans }}</a></li>
<li><a href="{{ addonsUrl.opera }}" target="_blank" rel="noopener">{{ 'howto.browser_addons.opera'|trans }}</a></li>
<li><a href="{{ addonsUrl.firefox }}" target="_blank">{{ 'howto.browser_addons.firefox'|trans }}</a></li>
<li><a href="{{ addonsUrl.chrome }}" target="_blank">{{ 'howto.browser_addons.chrome'|trans }}</a></li>
<li><a href="{{ addonsUrl.opera }}" target="_blank">{{ 'howto.browser_addons.opera'|trans }}</a></li>
</ul>
</div>
<div class="col s12">
<h5>{{ 'howto.top_menu.mobile_apps'|trans }}</h5>
<ul>
<li>Android: <a href="{{ addonsUrl.f_droid }}" target="_blank" rel="noopener">{{ 'howto.mobile_apps.android.via_f_droid'|trans }}</a> / <a href="{{ addonsUrl.google_play }}" target="_blank" rel="noopener">{{ 'howto.mobile_apps.android.via_google_play'|trans }}</a></li>
<li>Android: <a href="{{ addonsUrl.f_droid }}" target="_blank">{{ 'howto.mobile_apps.android.via_f_droid'|trans }}</a> / <a href="{{ addonsUrl.google_play }}" target="_blank">{{ 'howto.mobile_apps.android.via_google_play'|trans }}</a></li>
<li>iOS: <a href="{{ addonsUrl.ios }}" target="_blank">{{ 'howto.mobile_apps.ios'|trans }}</a></li>
<li>Windows Phone: <a href="{{ addonsUrl.windows }}" target="_blank" rel="noopener">{{ 'howto.mobile_apps.windows'|trans }}</a></li>
<li>Windows Phone: <a href="{{ addonsUrl.windows }}" target="_blank">{{ 'howto.mobile_apps.windows'|trans }}</a></li>
</ul>
</div>

View File

@ -8,11 +8,8 @@
<div class="{{ subClass|default('original grey-text') }}">
<a href="{{ entry.url|e }}" target="_blank" title="{{ entry.domainName|removeWww }}" class="tool grey-text">{{ entry.domainName|removeWww }}</a>
{% if withMetadata is defined %}
{% if withTags is defined %}
{% include "@WallabagCore/themes/material/Entry/_tags.html.twig" with {'tags': entry.tags | slice(0, 3), 'entryId': entry.id, 'listClass': ' hide-on-med-and-down'} only %}
<div class="reading-time grey-text">
<div class="card-reading-time">{% include "@WallabagCore/themes/material/Entry/_reading_time.html.twig" with {'entry': entry} only %}</div>
</div>
{% endif %}
</div>
</div>

View File

@ -1,11 +1,9 @@
<div class="card-action">
<div class="reading-time grey-text">
<div class="card-reading-time">{% include "@WallabagCore/themes/material/Entry/_reading_time.html.twig" with {'entry': entry} only %}</div>
<div class="card-created-at">
<i class="material-icons" title="{{ 'entry.view.created_at'|trans }}">today</i>
<span>&nbsp;{{ entry.createdAt|date('Y-m-d') }}</span>
</div>
</div>
<span class="reading-time grey-text">
{% include "@WallabagCore/themes/material/Entry/_reading_time.html.twig" with {'entry': entry} only %}
<i class="material-icons hide-on-med-and-down" title="{{ 'entry.view.created_at'|trans }}">today</i>
<span class="hide-on-med-and-down">&nbsp;{{ entry.createdAt|date('Y-m-d') }}</span>
</span>
<ul class="tools right">
<li>

View File

@ -1,11 +1,12 @@
<div class="card-stacked">
<div class="card-preview">
<a href="{{ path('view', { 'id': entry.id }) }}">
{% set previewClassModifier = entry.previewPicture ? '' : ' preview--default' %}
<span class="preview{{ previewClassModifier }}" style="background-image: url({{ entry.previewPicture | default(asset('wallassets/themes/_global/img/logo-square.svg')) }})"></span>
</a>
<div class="preview">
{% if entry.previewPicture is not null %}
<a href="{{ path('view', { 'id': entry.id }) }}">
<img src="{{ entry.previewPicture }}" />
</a>
{% endif %}
</div>
{% include "@WallabagCore/themes/material/Entry/Card/_content.html.twig" with {'entry': entry, 'withMetadata': true, 'subClass': 'metadata'} only %}
{% include "@WallabagCore/themes/material/Entry/Card/_content.html.twig" with {'entry': entry, 'withTags': true, 'subClass': 'metadata'} only %}
<ul class="tools-list hide-on-small-only">
<li>
<a title="{{ 'entry.list.toogle_as_read'|trans }}" class="tool grey-text" href="{{ path('archive_entry', { 'id': entry.id }) }}"><i class="material-icons">{% if entry.isArchived == 0 %}done{% else %}unarchive{% endif %}</i></a>

View File

@ -0,0 +1,7 @@
<div class="card">
<div class="card-body">
{% include "@WallabagCore/themes/material/Entry/Card/_content.html.twig" with {'entry': entry} only %}
</div>
{% include "@WallabagCore/themes/material/Entry/_card_actions.html.twig" with {'entry': entry} only %}
</div>

View File

@ -7,8 +7,7 @@
{% endfor %}
</ul>
<a href="{{ path('view', { 'id': entry.id }) }}">
{% set previewClassModifier = entry.previewPicture ? '' : ' preview--default' %}
<span class="preview{{ previewClassModifier }}" style="background-image: url({{ entry.previewPicture | default(asset('wallassets/themes/_global/img/logo-square.svg')) }})"></span>
<span class="preview" style="background-image: url({{ entry.previewPicture }})"></span>
</a>
</div>
{% include "@WallabagCore/themes/material/Entry/Card/_content.html.twig" with {'entry': entry, 'withPreview': true} only %}

View File

@ -39,9 +39,11 @@
<li id="entry-{{ entry.id|e }}" class="col {% if listMode == 0 %}l3 m6{% else %}collection-item{% endif %} s12">
{% if listMode == 1 %}
{% include "@WallabagCore/themes/material/Entry/_card_list.html.twig" with {'entry': entry} only %}
{% elseif entry.previewPicture is null %}
{% include "@WallabagCore/themes/material/Entry/_card_no_preview.html.twig" with {'entry': entry} only %}
{% elseif not entry.previewPicture is null and entry.mimetype starts with 'image/' %}
{% include "@WallabagCore/themes/material/Entry/_card_full_image.html.twig" with {'entry': entry} only %}
{% else %}
{% elseif not entry.previewPicture is null %}
{% include "@WallabagCore/themes/material/Entry/_card_preview.html.twig" with {'entry': entry} only %}
{% endif %}
</li>
@ -68,8 +70,8 @@
{% if craue_setting('export_epub') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'epub', 'tag' : currentTag }) }}">EPUB</a></li>{% endif %}
{% if craue_setting('export_mobi') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'mobi', 'tag' : currentTag }) }}">MOBI</a></li>{% endif %}
{% if craue_setting('export_pdf') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'pdf', 'tag' : currentTag }) }}">PDF</a></li>{% endif %}
{% if craue_setting('export_json') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'json', 'tag' : currentTag }) }}">JSON</a></li>{% endif %}
{% if craue_setting('export_csv') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'csv', 'tag' : currentTag }) }}">CSV</a></li>{% endif %}
{% if craue_setting('export_csv') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'json', 'tag' : currentTag }) }}">JSON</a></li>{% endif %}
{% if craue_setting('export_json') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'csv', 'tag' : currentTag }) }}">CSV</a></li>{% endif %}
{% if craue_setting('export_txt') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'txt', 'tag' : currentTag }) }}">TXT</a></li>{% endif %}
{% if craue_setting('export_xml') %}<li class="bold"><a class="waves-effect" href="{{ path('export_entries', { 'category': currentRoute, 'format': 'xml', 'tag' : currentTag }) }}">XML</a></li>{% endif %}
</ul>

View File

@ -46,7 +46,7 @@
</li>
<li class="bold border-bottom hide-on-med-and-down">
<a class="waves-effect collapsible-header original" href="{{ entry.url|e }}" target="_blank" rel="noopener">
<a class="waves-effect collapsible-header original" href="{{ entry.url|e }}" target="_blank">
<i class="material-icons small">link</i>
<span>{{ 'entry.view.left_menu.view_original_article'|trans }}</span>
</a>
@ -127,42 +127,42 @@
{% endif %}
{% if craue_setting('share_twitter') %}
<li>
<a href="https://twitter.com/home?status={{entry.title|striptags|url_encode}}%20{{ entry.url|url_encode }}%20via%20@wallabagapp" target="_blank" rel="noopener" class="tool icon-twitter" title="twitter">
<a href="https://twitter.com/home?status={{entry.title|striptags|url_encode}}%20{{ entry.url|url_encode }}%20via%20@wallabagapp" target="_blank" class="tool icon-twitter" title="twitter">
<span>twitter</span>
</a>
</li>
{% endif %}
{% if craue_setting('share_shaarli') %}
<li>
<a href="{{ craue_setting('shaarli_url') }}/index.php?post={{ entry.url|url_encode }}&amp;title={{ entry.title|striptags|url_encode }}&amp;tags={{ entry.tags|join(',')|striptags|url_encode }}{% if craue_setting('shaarli_share_origin_url') %}&amp;original_url={{ entry.originUrl|url_encode }}{% endif %}" target="_blank" rel="noopener" title="shaarli" class="tool icon-image shaarli">
<a href="{{ craue_setting('shaarli_url') }}/index.php?post={{ entry.url|url_encode }}&amp;title={{ entry.title|striptags|url_encode }}&amp;tags={{ entry.tags|join(',')|striptags|url_encode }}{% if craue_setting('shaarli_share_origin_url') %}&amp;original_url={{ entry.originUrl|url_encode }}{% endif %}" target="_blank" title="shaarli" class="tool icon-image shaarli">
<span>shaarli</span>
</a>
</li>
{% endif %}
{% if craue_setting('share_scuttle') %}
<li>
<a href="{{ craue_setting('scuttle_url') }}/bookmarks.php?action=add&amp;address={{ entry.url|url_encode }}&amp;title={{ entry.title|striptags|url_encode }}&amp;tags={{ entry.tags|join(',')|striptags|url_encode }}" target="_blank" rel="noopener" title="scuttle" class="tool icon-image scuttle">
<a href="{{ craue_setting('scuttle_url') }}/bookmarks.php?action=add&amp;address={{ entry.url|url_encode }}&amp;title={{ entry.title|striptags|url_encode }}&amp;tags={{ entry.tags|join(',')|striptags|url_encode }}" target="_blank" title="scuttle" class="tool icon-image scuttle">
<span>scuttle</span>
</a>
</li>
{% endif %}
{% if craue_setting('share_diaspora') %}
<li>
<a href="{{ craue_setting('diaspora_url') }}/bookmarklet?url={{ entry.url|url_encode }}&amp;title={{ entry.title|striptags|url_encode }}&amp;notes=&amp;v=1&amp;noui=1&amp;jump=doclose" target="_blank" rel="noopener" class="tool icon-image diaspora" title="diaspora">
<a href="{{ craue_setting('diaspora_url') }}/bookmarklet?url={{ entry.url|url_encode }}&amp;title={{ entry.title|striptags|url_encode }}&amp;notes=&amp;v=1&amp;noui=1&amp;jump=doclose" target="_blank" class="tool icon-image diaspora" title="diaspora">
<span>diaspora*</span>
</a>
</li>
{% endif %}
{% if craue_setting('share_unmark') %}
<li>
<a href="{{ craue_setting('unmark_url') }}/mark/add?url={{ entry.url|url_encode }}&amp;title={{entry.title|striptags|url_encode}}&amp;v=6" target="_blank" rel="noopener" class="tool icon-image unmark" title="unmark">
<a href="{{ craue_setting('unmark_url') }}/mark/add?url={{ entry.url|url_encode }}&amp;title={{entry.title|striptags|url_encode}}&amp;v=6" target="_blank" class="tool icon-image unmark" title="unmark">
<span>unmark.it</span>
</a>
</li>
{% endif %}
{% if craue_setting('carrot') %}
<li>
<a href="https://secure.carrot.org/GiveAndGetBack.do?url={{ entry.url|url_encode }}&amp;title={{ entry.title|striptags|url_encode }}" target="_blank" rel="noopener" title="carrot" class="tool icon-image carrot">
<a href="https://secure.carrot.org/GiveAndGetBack.do?url={{ entry.url|url_encode }}&amp;title={{ entry.title|striptags|url_encode }}" target="_blank" title="carrot" class="tool icon-image carrot">
<span>Carrot</span>
</a>
</li>
@ -209,7 +209,7 @@
</li>
<li class="bold">
<a class="waves-effect collapsible-header" href="mailto:siteconfig@wallabag.org?subject=Wrong%20display%20in%20wallabag&amp;body={{ entry.url|url_encode }}" title="{{ 'entry.view.left_menu.problem.description'|trans }}">
<a class="waves-effect collapsible-header" href="mailto:hello@wallabag.org?subject=Wrong%20display%20in%20wallabag&amp;body={{ entry.url|url_encode }}" title="{{ 'entry.view.left_menu.problem.description'|trans }}">
<i class="material-icons small">error</i>
<span>{{ 'entry.view.left_menu.problem.label'|trans }}</span>
</a>
@ -251,7 +251,7 @@
{% endif %}
<li>
<i class="material-icons link">link</i>
<a href="{{ entry.url|e }}" target="_blank" rel="noopener" title="{{ 'entry.view.original_article'|trans }} : {{ entry.title|striptags }}" class="tool">
<a href="{{ entry.url|e }}" target="_blank" title="{{ 'entry.view.original_article'|trans }} : {{ entry.title|striptags }}" class="tool">
{{ entry.domainName|removeWww }}
</a>
</li>
@ -262,7 +262,7 @@
{% if entry.originUrl is not empty %}
<li>
<i class="material-icons" title="{{ 'entry.view.provided_by'|trans }}">launch</i>
<a href="{{ entry.originUrl|e }}" target="_blank" rel="noopener" class="tool">
<a href="{{ entry.originUrl|e }}" target="_blank" class="tool">
{{ entry.originUrl|striptags|removeSchemeAndWww|truncate(32) }}
</a>
</li>
@ -275,6 +275,10 @@
{{ render(controller( "WallabagCoreBundle:Tag:addTagForm", { 'id': entry.id } )) }}
</div>
{% if entry.previewPicture is not null %}
<div><img class="preview" src="{{ entry.previewPicture }}" alt="{{ entry.title|striptags|default('entry.default_title'|trans)|raw }}" /></div>
{% endif %}
</aside>
<article>
{{ entry.content | raw }}

View File

@ -143,7 +143,7 @@
</div>
<div class="col s12 l4">
<p class="footer-text">
{{ 'footer.wallabag.powered_by'|trans }} <a target="_blank" rel="noopener" href="https://wallabag.org" class="grey-text text-lighten-4">wallabag</a>
{{ 'footer.wallabag.powered_by'|trans }} <a target="_blank" href="https://wallabag.org" class="grey-text text-lighten-4">wallabag</a>
<a class="grey-text text-lighten-4" href="{{ path('about') }}">{{ 'footer.wallabag.about'|trans|lower }}</a>
</p>
</div>

View File

@ -20,14 +20,15 @@ class Utils
}
/**
* For a given text, we calculate reading time for an article based on 200 words per minute.
* For a given text, we calculate reading time for an article
* based on 200 words per minute.
*
* @param string $text
* @param $text
*
* @return float
*/
public static function getReadingTime($text)
{
return floor(\count(preg_split('~([^\p{L}\p{N}\']+|(\p{Han}|\p{Hiragana}|\p{Katakana}|\p{Hangul}){1,2})~u', strip_tags($text))) / 200);
return floor(\count(preg_split('~[^\p{L}\p{N}\']+~u', strip_tags($text))) / 200);
}
}

View File

@ -52,13 +52,6 @@ abstract class AbstractConsumer
$this->import->setUser($user);
if (false === $this->import->validateEntry($storedEntry)) {
$this->logger->warning('Entry is invalid', ['entry' => $storedEntry]);
// return true to skip message
return true;
}
$entry = $this->import->parseEntry($storedEntry);
if (null === $entry) {

View File

@ -118,15 +118,6 @@ abstract class AbstractImport implements ImportInterface
*/
abstract public function parseEntry(array $importedEntry);
/**
* Validate that an entry is valid (like has some required keys, etc.).
*
* @param array $importedEntry
*
* @return bool
*/
abstract public function validateEntry(array $importedEntry);
/**
* Fetch content from the ContentProxy (using graby).
* If it fails return the given entry to be saved in all case (to avoid user to loose the content).
@ -150,9 +141,9 @@ abstract class AbstractImport implements ImportInterface
/**
* Parse and insert all given entries.
*
* @param array $entries
* @param $entries
*/
protected function parseEntries(array $entries)
protected function parseEntries($entries)
{
$i = 1;
$entryToBeFlushed = [];
@ -162,10 +153,6 @@ abstract class AbstractImport implements ImportInterface
$importedEntry = $this->setEntryAsRead($importedEntry);
}
if (false === $this->validateEntry($importedEntry)) {
continue;
}
$entry = $this->parseEntry($importedEntry);
if (null === $entry) {

View File

@ -77,7 +77,7 @@ abstract class BrowserImport extends AbstractImport
*/
public function parseEntry(array $importedEntry)
{
if ((!\array_key_exists('guid', $importedEntry) || (!\array_key_exists('id', $importedEntry))) && \is_array(reset($importedEntry))) {
if ((!array_key_exists('guid', $importedEntry) || (!array_key_exists('id', $importedEntry))) && \is_array(reset($importedEntry))) {
if ($this->producer) {
$this->parseEntriesForProducer($importedEntry);
@ -89,7 +89,7 @@ abstract class BrowserImport extends AbstractImport
return;
}
if (\array_key_exists('children', $importedEntry)) {
if (array_key_exists('children', $importedEntry)) {
if ($this->producer) {
$this->parseEntriesForProducer($importedEntry['children']);
@ -101,11 +101,11 @@ abstract class BrowserImport extends AbstractImport
return;
}
if (!\array_key_exists('uri', $importedEntry) && !\array_key_exists('url', $importedEntry)) {
if (!array_key_exists('uri', $importedEntry) && !array_key_exists('url', $importedEntry)) {
return;
}
$url = \array_key_exists('uri', $importedEntry) ? $importedEntry['uri'] : $importedEntry['url'];
$url = array_key_exists('uri', $importedEntry) ? $importedEntry['uri'] : $importedEntry['url'];
$existingEntry = $this->em
->getRepository('WallabagCoreBundle:Entry')
@ -126,7 +126,7 @@ abstract class BrowserImport extends AbstractImport
// update entry with content (in case fetching failed, the given entry will be return)
$this->fetchContent($entry, $data['url'], $data);
if (\array_key_exists('tags', $data)) {
if (array_key_exists('tags', $data)) {
$this->tagsAssigner->assignTagsToEntry(
$entry,
$data['tags']
@ -149,9 +149,9 @@ abstract class BrowserImport extends AbstractImport
/**
* Parse and insert all given entries.
*
* @param array $entries
* @param $entries
*/
protected function parseEntries(array $entries)
protected function parseEntries($entries)
{
$i = 1;
$entryToBeFlushed = [];

View File

@ -30,18 +30,6 @@ class ChromeImport extends BrowserImport
return 'import.chrome.description';
}
/**
* {@inheritdoc}
*/
public function validateEntry(array $importedEntry)
{
if (empty($importedEntry['url'])) {
return false;
}
return true;
}
/**
* {@inheritdoc}
*/
@ -57,7 +45,7 @@ class ChromeImport extends BrowserImport
'created_at' => substr($entry['date_added'], 0, 10),
];
if (\array_key_exists('tags', $entry) && '' !== $entry['tags']) {
if (array_key_exists('tags', $entry) && '' !== $entry['tags']) {
$data['tags'] = $entry['tags'];
}

View File

@ -30,18 +30,6 @@ class FirefoxImport extends BrowserImport
return 'import.firefox.description';
}
/**
* {@inheritdoc}
*/
public function validateEntry(array $importedEntry)
{
if (empty($importedEntry['uri'])) {
return false;
}
return true;
}
/**
* {@inheritdoc}
*/
@ -57,7 +45,7 @@ class FirefoxImport extends BrowserImport
'created_at' => substr($entry['dateAdded'], 0, 10),
];
if (\array_key_exists('tags', $entry) && '' !== $entry['tags']) {
if (array_key_exists('tags', $entry) && '' !== $entry['tags']) {
$data['tags'] = $entry['tags'];
}

View File

@ -105,18 +105,6 @@ class InstapaperImport extends AbstractImport
return true;
}
/**
* {@inheritdoc}
*/
public function validateEntry(array $importedEntry)
{
if (empty($importedEntry['url'])) {
return false;
}
return true;
}
/**
* {@inheritdoc}
*/

View File

@ -80,18 +80,6 @@ class PinboardImport extends AbstractImport
return true;
}
/**
* {@inheritdoc}
*/
public function validateEntry(array $importedEntry)
{
if (empty($importedEntry['href'])) {
return false;
}
return true;
}
/**
* {@inheritdoc}
*/

View File

@ -168,18 +168,6 @@ class PocketImport extends AbstractImport
$this->client = $client;
}
/**
* {@inheritdoc}
*/
public function validateEntry(array $importedEntry)
{
if (empty($importedEntry['resolved_url']) && empty($importedEntry['given_url'])) {
return false;
}
return true;
}
/**
* {@inheritdoc}
*
@ -206,10 +194,10 @@ class PocketImport extends AbstractImport
$this->fetchContent($entry, $url);
// 0, 1, 2 - 1 if the item is archived - 2 if the item should be deleted
$entry->setArchived(1 === (int) $importedEntry['status'] || $this->markAsRead);
$entry->setArchived(1 === $importedEntry['status'] || $this->markAsRead);
// 0 or 1 - 1 if the item is starred
$entry->setStarred(1 === (int) $importedEntry['favorite']);
// 0 or 1 - 1 If the item is starred
$entry->setStarred(1 === $importedEntry['favorite']);
$title = 'Untitled';
if (isset($importedEntry['resolved_title']) && '' !== $importedEntry['resolved_title']) {

View File

@ -80,18 +80,6 @@ class ReadabilityImport extends AbstractImport
return true;
}
/**
* {@inheritdoc}
*/
public function validateEntry(array $importedEntry)
{
if (empty($importedEntry['article__url'])) {
return false;
}
return true;
}
/**
* {@inheritdoc}
*/

View File

@ -86,18 +86,6 @@ abstract class WallabagImport extends AbstractImport
return $this;
}
/**
* {@inheritdoc}
*/
public function validateEntry(array $importedEntry)
{
if (empty($importedEntry['url'])) {
return false;
}
return true;
}
/**
* {@inheritdoc}
*/
@ -122,7 +110,7 @@ abstract class WallabagImport extends AbstractImport
// update entry with content (in case fetching failed, the given entry will be return)
$this->fetchContent($entry, $data['url'], $data);
if (\array_key_exists('tags', $data)) {
if (array_key_exists('tags', $data)) {
$this->tagsAssigner->assignTagsToEntry(
$entry,
$data['tags'],

View File

@ -61,7 +61,7 @@ class WallabagV1Import extends WallabagImport
$data['html'] = $this->fetchingErrorMessage;
}
if (\array_key_exists('tags', $entry) && '' !== $entry['tags']) {
if (array_key_exists('tags', $entry) && '' !== $entry['tags']) {
$data['tags'] = $entry['tags'];
}

View File

@ -74,7 +74,7 @@
<table cellpadding="0" cellspacing="0" border="0" align="center" id="card">
<tr>
<td style="padding: 20px;" width="96px" valign="top"><img class="image_fix" src="{{ absolute_url(asset('wallassets/themes/_global/img/logo-square.svg')) }}" alt="logo" title="{{ wallabag_url }}" style="width: 96px; height: 96px;" /></td>
<td style="padding: 20px;" width="96px" valign="top"><img class="image_fix" src="{{ absolute_url(asset('wallassets/themes/_global/img/logo-other_themes.png')) }}" alt="logo" title="{{ wallabag_url }}" style="width: 96px; height: 96px;" /></td>
<td style="padding: 20px; padding-left: 0;" valign="top" id="cell_desc">
<h1>wallabag</h1>
<h5>{{ "auth_code.on"|trans({}, 'wallabag_user') }} {{ wallabag_url }}</h5>

View File

@ -11,7 +11,7 @@
<main class="valign-wrapper">
<div class="valign row">
<div class="card sw">
<div class="center"><img src="{{ asset('wallassets/themes/_global/img/logo-wallabag.svg') }}" class="typo-logo" alt="wallabag logo" /></div>
<div class="center"><img src="{{ asset('wallassets/themes/_global/img/logo-wallabag.svg') }}" alt="wallabag logo" class="typo-logo" /></div>
{% block fos_user_content %}
{% endblock fos_user_content %}
</div>

View File

@ -56,20 +56,6 @@ class DeveloperControllerTest extends WallabagCoreTestCase
$this->assertArrayHasKey('refresh_token', $data);
}
public function testCreateTokenWithBadClientId()
{
$client = $this->getClient();
$client->request('POST', '/oauth/v2/token', [
'grant_type' => 'password',
'client_id' => '$WALLABAG_CLIENT_ID',
'client_secret' => 'secret',
'username' => 'admin',
'password' => 'mypassword',
]);
$this->assertSame(400, $client->getResponse()->getStatusCode());
}
public function testListingClient()
{
$this->logInAs('admin');

View File

@ -242,15 +242,6 @@ class EntryRestControllerTest extends WallabagApiTestCase
$this->assertSame(2, $content['limit']);
}
public function testGetStarredEntriesWithBadSort()
{
$this->client->request('GET', '/api/entries', ['starred' => 1, 'sort' => 'updated', 'order' => 'unknown']);
$this->assertSame(400, $this->client->getResponse()->getStatusCode());
$this->assertSame('application/json', $this->client->getResponse()->headers->get('Content-Type'));
}
public function testGetStarredEntries()
{
$this->client->request('GET', '/api/entries', ['starred' => 1, 'sort' => 'updated']);
@ -400,71 +391,29 @@ class EntryRestControllerTest extends WallabagApiTestCase
public function testDeleteEntry()
{
$em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
$entry = new Entry($em->getReference(User::class, 1));
$entry->setUrl('http://0.0.0.0/test-delete-entry');
$entry->setTitle('Test delete entry');
$em->persist($entry);
$em->flush();
$entry = $this->client->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository('WallabagCoreBundle:Entry')
->findOneByUser(1, ['id' => 'asc']);
$em->clear();
if (!$entry) {
$this->markTestSkipped('No content found in db.');
}
$e = [
'title' => $entry->getTitle(),
'url' => $entry->getUrl(),
'id' => $entry->getId(),
];
$this->client->request('DELETE', '/api/entries/' . $e['id'] . '.json');
$this->client->request('DELETE', '/api/entries/' . $entry->getId() . '.json');
$this->assertSame(200, $this->client->getResponse()->getStatusCode());
$content = json_decode($this->client->getResponse()->getContent(), true);
$this->assertSame($e['title'], $content['title']);
$this->assertSame($e['url'], $content['url']);
$this->assertSame($e['id'], $content['id']);
$this->assertSame($entry->getTitle(), $content['title']);
$this->assertSame($entry->getUrl(), $content['url']);
$this->assertSame($entry->getId(), $content['id']);
// We'll try to delete this entry again
$client = $this->createAuthorizedClient();
$client->request('DELETE', '/api/entries/' . $e['id'] . '.json');
$this->client->request('DELETE', '/api/entries/' . $entry->getId() . '.json');
$this->assertSame(404, $client->getResponse()->getStatusCode());
}
public function testDeleteEntryExpectId()
{
$em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
$entry = new Entry($em->getReference(User::class, 1));
$entry->setUrl('http://0.0.0.0/test-delete-entry-id');
$em->persist($entry);
$em->flush();
$em->clear();
$id = $entry->getId();
$this->client->request('DELETE', '/api/entries/' . $id . '.json?expect=id');
$this->assertSame(200, $this->client->getResponse()->getStatusCode());
$content = json_decode($this->client->getResponse()->getContent(), true);
$this->assertSame($id, $content['id']);
$this->assertArrayNotHasKey('url', $content);
// We'll try to delete this entry again
$client = $this->createAuthorizedClient();
$client->request('DELETE', '/api/entries/' . $id . '.json');
$this->assertSame(404, $client->getResponse()->getStatusCode());
}
public function testDeleteEntryExpectBadRequest()
{
$this->client->request('DELETE', '/api/entries/1.json?expect=badrequest');
$this->assertSame(400, $this->client->getResponse()->getStatusCode());
$this->assertSame(404, $this->client->getResponse()->getStatusCode());
}
public function testPostEntry()

View File

@ -7,8 +7,6 @@ use Wallabag\CoreBundle\Entity\Tag;
class TagRestControllerTest extends WallabagApiTestCase
{
private $otherUserTagLabel = 'bob';
public function testGetUserTags()
{
$this->client->request('GET', '/api/tags.json');
@ -21,33 +19,17 @@ class TagRestControllerTest extends WallabagApiTestCase
$this->assertArrayHasKey('id', $content[0]);
$this->assertArrayHasKey('label', $content[0]);
$tagLabels = array_map(function ($i) {
return $i['label'];
}, $content);
$this->assertNotContains($this->otherUserTagLabel, $tagLabels, 'There is a possible tag leak');
return end($content);
}
public function testDeleteUserTag()
{
$em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
$entry = $this->client->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository('WallabagCoreBundle:Entry')
->findOneWithTags($this->user->getId());
$entry = $entry[0];
$tagLabel = 'tagtest';
$tag = new Tag();
$tag->setLabel($tagLabel);
$em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
$em->persist($tag);
$entry->addTag($tag);
$em->persist($entry);
$em->flush();
$em->clear();
@ -71,16 +53,6 @@ class TagRestControllerTest extends WallabagApiTestCase
$this->assertNull($tag, $tagLabel . ' was removed because it begun an orphan tag');
}
public function testDeleteOtherUserTag()
{
$em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
$tag = $em->getRepository('WallabagCoreBundle:Tag')->findOneByLabel($this->otherUserTagLabel);
$this->client->request('DELETE', '/api/tags/' . $tag->getId() . '.json');
$this->assertSame(404, $this->client->getResponse()->getStatusCode());
}
public function dataForDeletingTagByLabel()
{
return [
@ -140,13 +112,6 @@ class TagRestControllerTest extends WallabagApiTestCase
$this->assertSame(404, $this->client->getResponse()->getStatusCode());
}
public function testDeleteTagByLabelOtherUser()
{
$this->client->request('DELETE', '/api/tag/label.json', ['tag' => $this->otherUserTagLabel]);
$this->assertSame(404, $this->client->getResponse()->getStatusCode());
}
/**
* @dataProvider dataForDeletingTagByLabel
*/
@ -215,11 +180,4 @@ class TagRestControllerTest extends WallabagApiTestCase
$this->assertSame(404, $this->client->getResponse()->getStatusCode());
}
public function testDeleteTagsByLabelOtherUser()
{
$this->client->request('DELETE', '/api/tags/label.json', ['tags' => $this->otherUserTagLabel]);
$this->assertSame(404, $this->client->getResponse()->getStatusCode());
}
}

View File

@ -167,13 +167,14 @@ class EntryControllerTest extends WallabagCoreTestCase
$this->assertContains('Google', $content->getTitle());
$this->assertSame('fr', $content->getLanguage());
$this->assertSame('2015-03-28 11:43:19', $content->getPublishedAt()->format('Y-m-d H:i:s'));
$this->assertArrayHasKey('x-frame-options', $content->getHeaders());
$this->assertSame('Morgane Tual', $author[0]);
$this->assertArrayHasKey('x-varnish1', $content->getHeaders());
$client->getContainer()->get('craue_config')->set('store_article_headers', 0);
}
public function testPostWithMultipleAuthors()
{
$url = 'https://www.liberation.fr/planete/2017/04/05/donald-trump-et-xi-jinping-tentative-de-flirt-en-floride_1560768';
$url = 'http://www.liberation.fr/planete/2017/04/05/donald-trump-et-xi-jinping-tentative-de-flirt-en-floride_1560768';
$this->logInAs('admin');
$client = $this->getClient();
@ -196,7 +197,6 @@ class EntryControllerTest extends WallabagCoreTestCase
->getRepository('WallabagCoreBundle:Entry')
->findByUrlAndUserId($url, $this->getLoggedInUserId());
$this->assertInstanceOf('Wallabag\CoreBundle\Entity\Entry', $content);
$authors = $content->getPublishedBy();
$this->assertSame('2017-04-05 19:26:13', $content->getPublishedAt()->format('Y-m-d H:i:s'));
$this->assertSame('fr', $content->getLanguage());

View File

@ -98,7 +98,7 @@ class ExportControllerTest extends WallabagCoreTestCase
$headers = $client->getResponse()->headers;
$this->assertSame('application/x-mobipocket-ebook', $headers->get('content-type'));
$this->assertSame('attachment; filename="' . $this->getSanitizedFilename($content->getTitle()) . '.mobi"', $headers->get('content-disposition'));
$this->assertSame('attachment; filename="' . preg_replace('/[^A-Za-z0-9\-]/', '', $content->getTitle()) . '.mobi"', $headers->get('content-disposition'));
$this->assertSame('binary', $headers->get('content-transfer-encoding'));
}
@ -126,7 +126,7 @@ class ExportControllerTest extends WallabagCoreTestCase
$headers = $client->getResponse()->headers;
$this->assertSame('application/pdf', $headers->get('content-type'));
$this->assertSame('attachment; filename="Tag foo bar articles.pdf"', $headers->get('content-disposition'));
$this->assertSame('attachment; filename="Tag_entries articles.pdf"', $headers->get('content-disposition'));
$this->assertSame('binary', $headers->get('content-transfer-encoding'));
}
@ -212,7 +212,7 @@ class ExportControllerTest extends WallabagCoreTestCase
$headers = $client->getResponse()->headers;
$this->assertSame('application/json', $headers->get('content-type'));
$this->assertSame('attachment; filename="' . $this->getSanitizedFilename($contentInDB->getTitle()) . '.json"', $headers->get('content-disposition'));
$this->assertSame('attachment; filename="' . $contentInDB->getTitle() . '.json"', $headers->get('content-disposition'));
$this->assertSame('UTF-8', $headers->get('content-transfer-encoding'));
$content = json_decode($client->getResponse()->getContent(), true);
@ -281,9 +281,4 @@ class ExportControllerTest extends WallabagCoreTestCase
$this->assertNotEmpty('created_at', (string) $content->entry[0]->created_at);
$this->assertNotEmpty('updated_at', (string) $content->entry[0]->updated_at);
}
private function getSanitizedFilename($title)
{
return preg_replace('/[^A-Za-z0-9\- \']/', '', iconv('utf-8', 'us-ascii//TRANSLIT', $title));
}
}

View File

@ -5,22 +5,26 @@ namespace Tests\Wallabag\CoreBundle\GuzzleSiteAuthenticator;
use Graby\SiteConfig\SiteConfig as GrabySiteConfig;
use Monolog\Handler\TestHandler;
use Monolog\Logger;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Tests\Wallabag\CoreBundle\WallabagCoreTestCase;
use Wallabag\CoreBundle\GuzzleSiteAuthenticator\GrabySiteConfigBuilder;
class GrabySiteConfigBuilderTest extends WallabagCoreTestCase
class GrabySiteConfigBuilderTest extends TestCase
{
/** @var \Wallabag\CoreBundle\GuzzleSiteAuthenticator\GrabySiteConfigBuilder */
protected $builder;
public function testBuildConfigExists()
{
/* @var \Graby\SiteConfig\ConfigBuilder|\PHPUnit_Framework_MockObject_MockObject */
$grabyConfigBuilderMock = $this->getMockBuilder('Graby\SiteConfig\ConfigBuilder')
->disableOriginalConstructor()
->getMock();
$grabySiteConfig = new GrabySiteConfig();
$grabySiteConfig->requires_login = true;
$grabySiteConfig->login_uri = 'http://api.example.com/login';
$grabySiteConfig->login_uri = 'http://www.example.com/login';
$grabySiteConfig->login_username_field = 'login';
$grabySiteConfig->login_password_field = 'password';
$grabySiteConfig->login_extra_fields = ['field=value'];
@ -28,7 +32,7 @@ class GrabySiteConfigBuilderTest extends WallabagCoreTestCase
$grabyConfigBuilderMock
->method('buildForHost')
->with('api.example.com')
->with('example.com')
->will($this->returnValue($grabySiteConfig));
$logger = new Logger('foo');
@ -39,8 +43,8 @@ class GrabySiteConfigBuilderTest extends WallabagCoreTestCase
->disableOriginalConstructor()
->getMock();
$siteCrentialRepo->expects($this->once())
->method('findOneByHostsAndUser')
->with(['api.example.com', '.example.com'], 1)
->method('findOneByHostAndUser')
->with('example.com', 1)
->willReturn(['username' => 'foo', 'password' => 'bar']);
$user = $this->getMockBuilder('Wallabag\UserBundle\Entity\User')
@ -55,18 +59,18 @@ class GrabySiteConfigBuilderTest extends WallabagCoreTestCase
$tokenStorage = new TokenStorage();
$tokenStorage->setToken($token);
$builder = new GrabySiteConfigBuilder(
$this->builder = new GrabySiteConfigBuilder(
$grabyConfigBuilderMock,
$tokenStorage,
$siteCrentialRepo,
$logger
);
$config = $builder->buildForHost('api.example.com');
$config = $this->builder->buildForHost('www.example.com');
$this->assertSame('api.example.com', $config->getHost());
$this->assertSame('example.com', $config->getHost());
$this->assertTrue($config->requiresLogin());
$this->assertSame('http://api.example.com/login', $config->getLoginUri());
$this->assertSame('http://www.example.com/login', $config->getLoginUri());
$this->assertSame('login', $config->getUsernameField());
$this->assertSame('password', $config->getPasswordField());
$this->assertSame(['field' => 'value'], $config->getExtraFields());
@ -81,6 +85,7 @@ class GrabySiteConfigBuilderTest extends WallabagCoreTestCase
public function testBuildConfigDoesntExist()
{
/* @var \Graby\SiteConfig\ConfigBuilder|\PHPUnit_Framework_MockObject_MockObject */
$grabyConfigBuilderMock = $this->getMockBuilder('\Graby\SiteConfig\ConfigBuilder')
->disableOriginalConstructor()
->getMock();
@ -98,8 +103,8 @@ class GrabySiteConfigBuilderTest extends WallabagCoreTestCase
->disableOriginalConstructor()
->getMock();
$siteCrentialRepo->expects($this->once())
->method('findOneByHostsAndUser')
->with(['unknown.com', '.com'], 1)
->method('findOneByHostAndUser')
->with('unknown.com', 1)
->willReturn(null);
$user = $this->getMockBuilder('Wallabag\UserBundle\Entity\User')
@ -114,14 +119,14 @@ class GrabySiteConfigBuilderTest extends WallabagCoreTestCase
$tokenStorage = new TokenStorage();
$tokenStorage->setToken($token);
$builder = new GrabySiteConfigBuilder(
$this->builder = new GrabySiteConfigBuilder(
$grabyConfigBuilderMock,
$tokenStorage,
$siteCrentialRepo,
$logger
);
$config = $builder->buildForHost('unknown.com');
$config = $this->builder->buildForHost('unknown.com');
$this->assertFalse($config);
@ -129,121 +134,4 @@ class GrabySiteConfigBuilderTest extends WallabagCoreTestCase
$this->assertCount(1, $records, 'One log was recorded');
}
public function testBuildConfigUserNotDefined()
{
$grabyConfigBuilderMock = $this->getMockBuilder('\Graby\SiteConfig\ConfigBuilder')
->disableOriginalConstructor()
->getMock();
$grabyConfigBuilderMock
->method('buildForHost')
->with('unknown.com')
->will($this->returnValue(new GrabySiteConfig()));
$logger = new Logger('foo');
$handler = new TestHandler();
$logger->pushHandler($handler);
$siteCrentialRepo = $this->getMockBuilder('Wallabag\CoreBundle\Repository\SiteCredentialRepository')
->disableOriginalConstructor()
->getMock();
$tokenStorage = new TokenStorage();
$builder = new GrabySiteConfigBuilder(
$grabyConfigBuilderMock,
$tokenStorage,
$siteCrentialRepo,
$logger
);
$config = $builder->buildForHost('unknown.com');
$this->assertFalse($config);
}
public function dataProviderCredentials()
{
return [
[
'host' => 'example.com',
],
[
'host' => 'other.example.com',
],
[
'host' => 'paywall.example.com',
'expectedUsername' => 'paywall.example',
'expectedPassword' => 'bar',
],
[
'host' => 'api.super.com',
'expectedUsername' => '.super',
'expectedPassword' => 'bar',
],
[
'host' => '.super.com',
'expectedUsername' => '.super',
'expectedPassword' => 'bar',
],
];
}
/**
* @dataProvider dataProviderCredentials
*/
public function testBuildConfigWithDbAccess($host, $expectedUsername = null, $expectedPassword = null)
{
$grabyConfigBuilderMock = $this->getMockBuilder('Graby\SiteConfig\ConfigBuilder')
->disableOriginalConstructor()
->getMock();
$grabySiteConfig = new GrabySiteConfig();
$grabySiteConfig->requires_login = true;
$grabySiteConfig->login_uri = 'http://api.example.com/login';
$grabySiteConfig->login_username_field = 'login';
$grabySiteConfig->login_password_field = 'password';
$grabySiteConfig->login_extra_fields = ['field=value'];
$grabySiteConfig->not_logged_in_xpath = '//div[@class="need-login"]';
$grabyConfigBuilderMock
->method('buildForHost')
->with($host)
->will($this->returnValue($grabySiteConfig));
$user = $this->getMockBuilder('Wallabag\UserBundle\Entity\User')
->disableOriginalConstructor()
->getMock();
$user->expects($this->once())
->method('getId')
->willReturn(1);
$token = new UsernamePasswordToken($user, 'pass', 'provider');
$tokenStorage = new TokenStorage();
$tokenStorage->setToken($token);
$logger = new Logger('foo');
$handler = new TestHandler();
$logger->pushHandler($handler);
$builder = new GrabySiteConfigBuilder(
$grabyConfigBuilderMock,
$tokenStorage,
$this->getClient()->getContainer()->get('wallabag_core.site_credential_repository'),
$logger
);
$config = $builder->buildForHost($host);
if (null === $expectedUsername && null === $expectedPassword) {
$this->assertFalse($config);
return;
}
$this->assertSame($expectedUsername, $config->getUsername());
$this->assertSame($expectedPassword, $config->getPassword());
}
}

View File

@ -531,377 +531,6 @@ class ContentProxyTest extends TestCase
$this->assertSame('1.1.1.1', $entry->getDomainName());
}
public function testWebsiteWithValidUTF8Title_doNothing()
{
// You can use https://www.online-toolz.com/tools/text-hex-convertor.php to convert UTF-8 text <=> hex
// See http://graphemica.com for more info about the characters
// '😻z' (U+1F63B or F09F98BB; U+2124 or E284A4; U+007A or 7A) in hexadecimal and UTF-8
$actualTitle = $this->hexToStr('F09F98BB' . 'E284A4' . '7A');
$tagger = $this->getTaggerMock();
$tagger->expects($this->once())
->method('tag');
$graby = $this->getMockBuilder('Graby\Graby')
->setMethods(['fetchContent'])
->disableOriginalConstructor()
->getMock();
$graby->expects($this->any())
->method('fetchContent')
->willReturn([
'html' => false,
'title' => $actualTitle,
'url' => '',
'content_type' => 'text/html',
'language' => '',
]);
$proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage);
$entry = new Entry(new User());
$proxy->updateEntry($entry, 'http://0.0.0.0');
// '😻z' (U+1F63B or F09F98BB; U+2124 or E284A4; U+007A or 7A) in hexadecimal and UTF-8
$expectedTitle = 'F09F98BB' . 'E284A4' . '7A';
$this->assertSame($expectedTitle, $this->strToHex($entry->getTitle()));
}
public function testWebsiteWithInvalidUTF8Title_removeInvalidCharacter()
{
// See http://graphemica.com for more info about the characters
// 'a€b' (61;80;62) in hexadecimal and WINDOWS-1252 - but 80 is a invalid UTF-8 character.
// The correct UTF-8 € character (U+20AC) is E282AC
$actualTitle = $this->hexToStr('61' . '80' . '62');
$tagger = $this->getTaggerMock();
$tagger->expects($this->once())
->method('tag');
$graby = $this->getMockBuilder('Graby\Graby')
->setMethods(['fetchContent'])
->disableOriginalConstructor()
->getMock();
$graby->expects($this->any())
->method('fetchContent')
->willReturn([
'html' => false,
'title' => $actualTitle,
'url' => '',
'content_type' => 'text/html',
'language' => '',
]);
$proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage);
$entry = new Entry(new User());
$proxy->updateEntry($entry, 'http://0.0.0.0');
// 'ab' (61;62) because all invalid UTF-8 character (like 80) are removed
$expectedTitle = '61' . '62';
$this->assertSame($expectedTitle, $this->strToHex($entry->getTitle()));
}
public function testPdfWithUTF16BETitle_convertToUTF8()
{
// See http://graphemica.com for more info about the characters
// '😻' (U+1F63B;D83DDE3B) in hexadecimal and as UTF16BE
$actualTitle = $this->hexToStr('D83DDE3B');
$tagger = $this->getTaggerMock();
$tagger->expects($this->once())
->method('tag');
$graby = $this->getMockBuilder('Graby\Graby')
->setMethods(['fetchContent'])
->disableOriginalConstructor()
->getMock();
$graby->expects($this->any())
->method('fetchContent')
->willReturn([
'html' => false,
'title' => $actualTitle,
'url' => '',
'content_type' => 'application/pdf',
'language' => '',
]);
$proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage);
$entry = new Entry(new User());
$proxy->updateEntry($entry, 'http://0.0.0.0');
// '😻' (U+1F63B or F09F98BB) in hexadecimal and UTF-8
$expectedTitle = 'F09F98BB';
$this->assertSame($expectedTitle, $this->strToHex($entry->getTitle()));
}
public function testPdfWithUTF8Title_doNothing()
{
// See http://graphemica.com for more info about the characters
// '😻' (U+1F63B;D83DDE3B) in hexadecimal and as UTF8
$actualTitle = $this->hexToStr('F09F98BB');
$tagger = $this->getTaggerMock();
$tagger->expects($this->once())
->method('tag');
$graby = $this->getMockBuilder('Graby\Graby')
->setMethods(['fetchContent'])
->disableOriginalConstructor()
->getMock();
$graby->expects($this->any())
->method('fetchContent')
->willReturn([
'html' => false,
'title' => $actualTitle,
'url' => '',
'content_type' => 'application/pdf',
'language' => '',
]);
$proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage);
$entry = new Entry(new User());
$proxy->updateEntry($entry, 'http://0.0.0.0');
// '😻' (U+1F63B or F09F98BB) in hexadecimal and UTF-8
$expectedTitle = 'F09F98BB';
$this->assertSame($expectedTitle, $this->strToHex($entry->getTitle()));
}
public function testPdfWithWINDOWS1252Title_convertToUTF8()
{
// See http://graphemica.com for more info about the characters
// '€' (80) in hexadecimal and WINDOWS-1252
$actualTitle = $this->hexToStr('80');
$tagger = $this->getTaggerMock();
$tagger->expects($this->once())
->method('tag');
$graby = $this->getMockBuilder('Graby\Graby')
->setMethods(['fetchContent'])
->disableOriginalConstructor()
->getMock();
$graby->expects($this->any())
->method('fetchContent')
->willReturn([
'html' => false,
'title' => $actualTitle,
'url' => '',
'content_type' => 'application/pdf',
'language' => '',
]);
$proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage);
$entry = new Entry(new User());
$proxy->updateEntry($entry, 'http://0.0.0.0');
// '€' (U+20AC or E282AC) in hexadecimal and UTF-8
$expectedTitle = 'E282AC';
$this->assertSame($expectedTitle, $this->strToHex($entry->getTitle()));
}
public function testPdfWithInvalidCharacterInTitle_removeInvalidCharacter()
{
// See http://graphemica.com for more info about the characters
// '😻<F09F98BB>z' (U+1F63B or F09F98BB; U+2124 or E284A4; invalid character 81; U+007A or 7A) in hexadecimal and UTF-8
// 0x81 is not a valid character for UTF16, UTF8 and WINDOWS-1252
$actualTitle = $this->hexToStr('F09F98BB' . 'E284A4' . '81' . '7A');
$tagger = $this->getTaggerMock();
$tagger->expects($this->once())
->method('tag');
$graby = $this->getMockBuilder('Graby\Graby')
->setMethods(['fetchContent'])
->disableOriginalConstructor()
->getMock();
$graby->expects($this->any())
->method('fetchContent')
->willReturn([
'html' => false,
'title' => $actualTitle,
'url' => '',
'content_type' => 'application/pdf',
'language' => '',
]);
$proxy = new ContentProxy($graby, $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage);
$entry = new Entry(new User());
$proxy->updateEntry($entry, 'http://0.0.0.0');
// '😻z' (U+1F63B or F09F98BB; U+2124 or E284A4; U+007A or 7A) in hexadecimal and UTF-8
// the 0x81 (represented by <20>) is invalid for UTF16, UTF8 and WINDOWS-1252 and is removed
$expectedTitle = 'F09F98BB' . 'E284A4' . '7A';
$this->assertSame($expectedTitle, $this->strToHex($entry->getTitle()));
}
/**
* Data provider for testWithChangedUrl.
*
* Arrays contain the following values:
* $entry_url
* $origin_url
* $content_url
* $expected_entry_url
* $expected_origin_url
* $expected_domain
*/
public function dataForChangedUrl()
{
return [
'normal' => [
'http://0.0.0.0',
null,
'http://1.1.1.1',
'http://1.1.1.1',
'http://0.0.0.0',
'1.1.1.1',
],
'origin already set' => [
'http://0.0.0.0',
'http://hello',
'http://1.1.1.1',
'http://1.1.1.1',
'http://hello',
'1.1.1.1',
],
'trailing slash' => [
'https://example.com/hello-world',
null,
'https://example.com/hello-world/',
'https://example.com/hello-world/',
null,
'example.com',
],
'query string in fetched content' => [
'https://example.org/hello',
null,
'https://example.org/hello?world=1',
'https://example.org/hello?world=1',
'https://example.org/hello',
'example.org',
],
'fragment in fetched content' => [
'https://example.org/hello',
null,
'https://example.org/hello#world',
'https://example.org/hello',
null,
'example.org',
],
'fragment and query string in fetched content' => [
'https://example.org/hello',
null,
'https://example.org/hello?foo#world',
'https://example.org/hello?foo#world',
'https://example.org/hello',
'example.org',
],
'different path and query string in fetch content' => [
'https://example.org/hello',
null,
'https://example.org/world?foo',
'https://example.org/world?foo',
'https://example.org/hello',
'example.org',
],
'feedproxy ignore list test' => [
'http://feedproxy.google.com/~r/Wallabag/~3/helloworld',
null,
'https://example.org/hello-wallabag',
'https://example.org/hello-wallabag',
null,
'example.org',
],
'feedproxy ignore list test with origin url already set' => [
'http://feedproxy.google.com/~r/Wallabag/~3/helloworld',
'https://example.org/this-is-source',
'https://example.org/hello-wallabag',
'https://example.org/hello-wallabag',
'https://example.org/this-is-source',
'example.org',
],
'lemonde ignore pattern test' => [
'http://www.lemonde.fr/tiny/url',
null,
'http://example.com/hello-world',
'http://example.com/hello-world',
null,
'example.com',
],
];
}
/**
* @dataProvider dataForChangedUrl
*/
public function testWithChangedUrl($entry_url, $origin_url, $content_url, $expected_entry_url, $expected_origin_url, $expected_domain)
{
$tagger = $this->getTaggerMock();
$tagger->expects($this->once())
->method('tag');
$proxy = new ContentProxy((new Graby()), $tagger, $this->getValidator(), $this->getLogger(), $this->fetchingErrorMessage, true);
$entry = new Entry(new User());
$entry->setOriginUrl($origin_url);
$proxy->updateEntry(
$entry,
$entry_url,
[
'html' => false,
'title' => '',
'url' => $content_url,
'content_type' => '',
'language' => '',
],
true
);
$this->assertSame($expected_entry_url, $entry->getUrl());
$this->assertSame($expected_domain, $entry->getDomainName());
$this->assertSame($expected_origin_url, $entry->getOriginUrl());
}
/**
* https://stackoverflow.com/a/18506801.
*
* @param $string
*
* @return string
*/
private function strToHex($string)
{
$hex = '';
for ($i = 0; $i < \strlen($string); ++$i) {
$ord = \ord($string[$i]);
$hexCode = dechex($ord);
$hex .= substr('0' . $hexCode, -2);
}
return strtoupper($hex);
}
/**
* https://stackoverflow.com/a/18506801.
*
* @param $hex
*
* @return string
*/
private function hexToStr($hex)
{
$string = '';
for ($i = 0; $i < \strlen($hex) - 1; $i += 2) {
$string .= \chr(hexdec($hex[$i] . $hex[$i + 1]));
}
return $string;
}
private function getTaggerMock()
{
return $this->getMockBuilder(RuleBasedTagger::class)

View File

@ -11,9 +11,9 @@ class UtilsTest extends TestCase
/**
* @dataProvider examples
*/
public function testCorrectWordsCountForDifferentLanguages($filename, $text, $expectedCount)
public function testCorrectWordsCountForDifferentLanguages($text, $expectedCount)
{
static::assertSame((float) $expectedCount, Utils::getReadingTime($text), 'Reading time for: ' . $filename);
static::assertSame((float) $expectedCount, Utils::getReadingTime($text));
}
public function examples()
@ -21,17 +21,7 @@ class UtilsTest extends TestCase
$examples = [];
$finder = (new Finder())->in(__DIR__ . '/samples');
foreach ($finder->getIterator() as $file) {
preg_match('/-----CONTENT-----\s*(.*?)\s*-----READING_TIME-----\s*(.*)/sx', $file->getContents(), $match);
if (3 !== \count($match)) {
throw new \Exception('Sample file "' . $file->getRelativePathname() . '" as wrong definition, see README.');
}
$examples[] = [
$file->getRelativePathname(),
$match[1], // content
$match[2], // reading time
];
$examples[] = [$file->getContents(), 1];
}
return $examples;

View File

@ -1,5 +0,0 @@
Defined language sample should use the following structure:
-----CONTENT-----
-----READING_TIME-----

View File

@ -1,10 +0,0 @@
-----CONTENT-----
职然问讲念谷月挂大报住本読能录要褐込。料士纸木陈与兴组静终図问有。今観深车相环学俳健越増职県県多券报。雪月批导掲稿家缝城间真中崩図人连。前担写治芸面毎作似水州稿注球戦頃。済方宮安目垣強入料会先呼略。計定設負財作覧経己員事田事球岡示差学。最院書模婚金回禁朝船教任分禁検理慮宿。
変送调指式真気交现上様女限宅复。禁业稿者普视想来木残止者済断式安。万致相领鉄再改界逮由竹式元最台変。済问活助库脳部风政京転说区変。文図化仙政常地里芸上褒前読望误记温政信土。惑育候当人万部逮重申結標番業望般。断瀬後社天打日資交献秀世覧第。補当編里身社記利件部夜中心掲大。
时大栗夜测署市要纯京挙化済负品。天最场情算掲放故手茨指岛然渡活民年。第纯交一特问明室试賛际者建。论铜所常縄一広気特秋提公茶可満编旅相変権。
兵线済来先决模入供定树希逮技鉄多连写塩。着刊禁浩歩人仕设谢争关周徒今高。十育幕桂球门载任快毎社洋着道育纸格幻末。关机高害通方纳狱社州要北相持中表。郎市真提里过何连地更重都山割周。
-----READING_TIME-----
1

View File

@ -1,10 +1,7 @@
-----CONTENT-----
Лорем ипсум долор сит амет, ех цум иллуд деленит, пер регионе фацилис те. Еи мел видит саепе интеллегам, яуас маиестатис цонституам яуо ат, цивибус реформиданс нецесситатибус ид яуи. Импетус тациматес пертинах ад еум. Усу еу легере бландит.
Ан меа тритани иуварет, иллум сцаевола легендос ат меа, дебитис импедит нусяуам ест ад. Не маиорум молестие цотидиеяуе вис. Иисяуе цонцлудатуряуе меи еу, татион цонсецтетуер еи про. Либер риденс ид хас, ид цонсул сенсерит пертинациа меа. Фацер молестиае цомпрехенсам ад еум, ин хис апеириан вивендум. Яуи аудире епицуреи иудицабит ат, веро хабео вертерем ад иус. Бонорум плацерат ин вис, сеа но оцурререт принципес интерессет, хас ет дицерет диспутандо.
Яуо цу цлита оцурререт. Сонет менандри ин сеа. Еум те нонумы вертерем. Вирис еяуидем фацилиси ет вим, делицата интеллегат иус ин. Ид дицат суммо витае вел, алияуип делецтус те дуо, цу вих хинц дуис видиссе. Нец цу фацилис урбанитас, алиа инсоленс ассуеверит при ут.
Яуаеяуе абхорреант инцоррупте не сеа, еу еирмод ерудити вих. Вел оптион тритани цоррумпит те. Поссе сусципит губергрен ут мел, ет еос ириуре менандри еффициенди. Те сале нулла цонсецтетуер сеа, меа не прима алиенум еффициантур. При ет воцибус реформиданс, темпор албуциус сед ан. Еи утрояуе волумус иус, атяуи цонгуе но меи.
-----READING_TIME-----
1
Яуаеяуе абхорреант инцоррупте не сеа, еу еирмод ерудити вих. Вел оптион тритани цоррумпит те. Поссе сусципит губергрен ут мел, ет еос ириуре менандри еффициенди. Те сале нулла цонсецтетуер сеа, меа не прима алиенум еффициантур. При ет воцибус реформиданс, темпор албуциус сед ан. Еи утрояуе волумус иус, атяуи цонгуе но меи.

View File

@ -1,4 +1,3 @@
-----CONTENT-----
Λορεμ ιπσθμ δολορ σιτ αμετ, ηασ νο θταμθρ qθαεqθε ρεπρεηενδθντ. Ναμ λατινε προμπτα qθαερενδθμ ιδ. Νεc ει φαρ cονcλθδατθρqθε, vολθπτθα vολθπταρια εφφιcιενδι αδ προ, νε σεα ασσεντιορ δεφινιεβασ. Μεα αγαμ ειθσ δολορε ετ, ηισ ει cορπορα περφεcτο. Vιξ cιβο δελενιτ νε, jθστο ριδενσ οπορτερε σεδ ιδ.
Ηισ νισλ ιθvαρετ γθβεργρεν εξ. Εθμ ιμπεδιτ δετραξιτ ινιμισ ατ, αλια βλανδιτ δθο εα, μεα ιλλθδ επιρι cονσετετθρ αδ. Ιλλθδ γραεcε δελενιτι ηισ νο. Νεc ιδ ριδενσ εθισμοδ περιcθλισ, vισ αδ λαβοραμθσ περσεcθτι. Ιθσ εα λθπτατθμ αλιανδο δισπθτανδο.
@ -7,6 +6,4 @@
Cθ σεδ αλβθcιθσ ποστθλαντ. Vιξ ιδ ηομερο περcιπιτ cονcεπταμ. Ιν vιμ λιβρισ vιδερερ, εξ vισ αλιι ερρορ. Vιξ λοβορτισ ασσεντιορ cοντεντιονεσ τε, νε ηασ δεcορε περcιπιτθρ. Εστ εξ δισπθτατιονι δεφινιτιονεμ, qθοδ πηαεδρθμ προ εθ, εξ ηασ ιντεγρε ελιγενδι cονσεcτετθερ.
Ιθσ μολλισ ειρμοδ νο, vιξ νοστρθμ cονσετετθρ ει. Ιθδιcορτερεμ λθcιλιθσι τε, νε προμπτα θτροqθε αccομμοδαρε περ. Φαcετε μανδαμθσ ηασ εξ, λιβερ δεβετ εθμ εξ, vιξ ιδ διρετ σιγνιφερθμqθε. Εθ vιξ vοντ.
-----READING_TIME-----
1
Ιθσ μολλισ ειρμοδ νο, vιξ νοστρθμ cονσετετθρ ει. Ιθδιcορτερεμ λθcιλιθσι τε, νε προμπτα θτροqθε αccομμοδαρε περ. Φαcετε μανδαμθσ ηασ εξ, λιβερ δεβετ εθμ εξ, vιξ ιδ διρετ σιγνιφερθμqθε. Εθ vιξ vοντ.

View File

@ -1,10 +0,0 @@
-----CONTENT-----
聞7配なク時初かきぴ触整ヨ国鴨覧女ミ将増3部ゅ見荷や言企まげやラ千第ロル企族リた期寄け。戦ト理載コミチヒ芸面だ会入テヒロソ一期ナトヒ試鮮せお天出並ぞる体森ヘツ決市ね地各ナク強町ず前目とまなを活直オ携握湯りよ。
流ムワ作大禁ヒフ断日ヱ断千ね消諸もとぐろ中勧リ配年リ文7茅ろへりめ辺渡フ三負安ぼ国撮ライム以逃めじット州67棋うきゃ。催キケ者乗フヒソツ染64崎ク捉示よぴふら道世へび属品おく西捕ニレ交重イフ式買散ル展五めづっイ鎧属ざごび数開キハツ聞続表クシタ補球ソウ禁源託ひれも。
季手ッがふ挙思メ勢1使すけねげ日熱争らあふか位義エコ望桑安く決管ーひ広間キヱ皇北ょはこ養山ミ放見負さぞて故携訃畑港ひわン。著支にふみ意豊ラだ球監トクユ馬惨が抱審リヒ労厚ゅぽひ継貸ミ果疑文キヤ闘府兼ユカシト多不っあ財責エ速訴径猶げすぽ。
了摘見いぶころ会料へゆぱ法利コツハリ統財千りイ伝年りぜ提社ロ片追ごー合作イカシニ感山よち真器敗香レれさ。視シ探大イ令69真ケトヱ便都ケホワナ境号ヱカオハ一助む関念ろんび幼脚要だ客投ヱハイ針教ヒウラ階担うスりね袖陸ょげけ同講料全ヤ催宮補ゆ徳就画圧愛め。
-----READING_TIME-----
1

View File

@ -1,10 +0,0 @@
-----CONTENT-----
국군은 국가의 안전보장과 국토방위의 신성한 의무를 수행함을 사명으로 하며, 대통령이 임시회의 집회를 요구할 때에는 기간과 집회요구의 이유를 명시하여야 한다. 정당의 목적이나 활동이 민주적 기본질서에 위배될 때에는 정부는 헌법재판소에 그 해산을 제소할 수 있고. 감사위원은 원장의 제청으로 대통령이 임명하고.
대한민국의 주권은 국민에게 있고, 국회는 국민의 보통·평등·직접·비밀선거에 의하여 선출된 국회의원으로 구성한다. 국가는 농업 및 어업을 보호·육성하기 위하여 농·어촌종합개발과 그 지원등 필요한 계획을 수립·시행하여야 한다. 대통령의 임기연장 또는 중임변경을 위한 헌법개정은 그 헌법개정 제안 당시의 대통령에 대하여는 효력이 없다.
국회가 재적의원 과반수의 찬성으로 계엄의 해제를 요구한 때에는 대통령은 이를 해제하여야 한다, 선거에 관한 경비는 법률이 정하는 경우를 제외하고는 정당 또는 후보자에게 부담시킬 수 없다. 그 정치적 중립성은 준수된다. 헌법개정안은 국회가 의결한 후 30일 이내에 국민투표에 붙여 국회의원선거권자 과반수의 투표와 투표자 과반수의 찬성을 얻어야 한다.
내부규율과 사무처리에 관한 규칙을 제정할 수 있다. 대통령에 대한 탄핵소추는 국회재적의원 과반수의 발의와 국회재적의원 3분의 2 이상의 찬성이 있어야 한다. 대통령은 국가의 원수이며. 대통령이 궐위된 때 또는 대통령 당선자가 사망하거나 판결 기타의 사유로 그 자격을 상실한 때에는 60일 이내에 후임자를 선거한다.
-----READING_TIME-----
2

View File

@ -1,4 +1,3 @@
-----CONTENT-----
Lorem ipsum dolor sit amet, pro vivendo oporteat pertinacia ei. Vim fabellas molestiae cu, vel nibh legimus ea, in qui atomorum democritum. Ius ne agam soluta ignota, his sale aperiri complectitur te, omnis volumus accusam an eos. Ut mentitum appetere mel, minim temporibus eloquentiam sea ea.
Tation nominati pro ad. Pri eros eloquentiam reformidans ea, et liber epicurei erroribus pro, pri patrioque repudiandae et. Cetero perfecto at eam. Eros hendrerit constituto vix at, brute aperiri adolescens pro eu. Vix lucilius consulatu ei, ullum tantas munere vel in, regione feugiat eligendi at eam.
@ -7,6 +6,4 @@ Eam an lucilius iracundia, audire diceret facilisi his in, ex paulo pertinacia p
Nec ut quod probo eligendi, cu dico iriure aperiam vis. Augue causae abhorreant per ut, iriure repudiandae no nam, exerci equidem deleniti nam te. Et duo saperet debitis adipiscing, quo odio audiam no, ex iudico delenit propriae duo. Eu eum eros abhorreant, an tractatos expetendis est.
Vix.
-----READING_TIME-----
1
Vix.

View File

@ -114,15 +114,13 @@ class InstapaperControllerTest extends WallabagCoreTestCase
->get('doctrine.orm.entity_manager')
->getRepository('WallabagCoreBundle:Entry')
->findByUrlAndUserId(
'https://www.liberation.fr/societe/2012/12/06/baumettes-un-tour-en-cellule_865551',
'http://www.liberation.fr/societe/2012/12/06/baumettes-un-tour-en-cellule_865551',
$this->getLoggedInUserId()
);
$this->assertInstanceOf('Wallabag\CoreBundle\Entity\Entry', $content);
$this->assertNotEmpty($content->getMimetype(), 'Mimetype for https://www.liberation.fr is ok');
$this->assertNotEmpty($content->getPreviewPicture(), 'Preview picture for https://www.liberation.fr is ok');
$this->assertNotEmpty($content->getLanguage(), 'Language for https://www.liberation.fr is ok');
$this->assertNotEmpty($content->getMimetype(), 'Mimetype for http://www.liberation.fr is ok');
$this->assertNotEmpty($content->getPreviewPicture(), 'Preview picture for http://www.liberation.fr is ok');
$this->assertNotEmpty($content->getLanguage(), 'Language for http://www.liberation.fr is ok');
$this->assertContains('foot', $content->getTags(), 'It includes the "foot" tag');
$this->assertSame(1, \count($content->getTags()));
$this->assertInstanceOf(\DateTime::class, $content->getCreatedAt());

View File

@ -115,16 +115,16 @@ class WallabagV2ControllerTest extends WallabagCoreTestCase
->get('doctrine.orm.entity_manager')
->getRepository('WallabagCoreBundle:Entry')
->findByUrlAndUserId(
'https://www.liberation.fr/planete/2015/10/26/refugies-l-ue-va-creer-100-000-places-d-accueil-dans-les-balkans_1408867',
'http://www.liberation.fr/planete/2015/10/26/refugies-l-ue-va-creer-100-000-places-d-accueil-dans-les-balkans_1408867',
$this->getLoggedInUserId()
);
$this->assertInstanceOf('Wallabag\CoreBundle\Entity\Entry', $content);
// empty because it wasn't re-imported
$this->assertEmpty($content->getMimetype(), 'Mimetype for https://www.liberation.fr is empty');
$this->assertEmpty($content->getPreviewPicture(), 'Preview picture for https://www.liberation.fr is empty');
$this->assertEmpty($content->getLanguage(), 'Language for https://www.liberation.fr is empty');
$this->assertEmpty($content->getMimetype(), 'Mimetype for http://www.liberation.fr is empty');
$this->assertEmpty($content->getPreviewPicture(), 'Preview picture for http://www.liberation.fr is empty');
$this->assertEmpty($content->getLanguage(), 'Language for http://www.liberation.fr is empty');
$tags = $content->getTags();
$this->assertContains('foot', $tags, 'It includes the "foot" tag');

View File

@ -226,13 +226,6 @@ class PocketImportTest extends TestCase
->method('getRepository')
->willReturn($entryRepo);
$this->em
->expects($this->any())
->method('persist')
->with($this->callback(function ($persistedEntry) {
return $persistedEntry->isArchived() && $persistedEntry->isStarred();
}));
$entry = new Entry($this->user);
$this->contentProxy

View File

@ -1,5 +1,5 @@
URL,Title,Selection,Folder
https://www.liberation.fr/societe/2012/12/06/baumettes-un-tour-en-cellule_865551,Baumettes : un tour en cellule,,Unread
http://www.liberation.fr/societe/2012/12/06/baumettes-un-tour-en-cellule_865551,Baumettes : un tour en cellule,,Unread
https://redditblog.com/2016/09/20/amp-and-reactredux/,AMP and React+Redux: Why Not?,,Archive
https://medium.com/@the_minh/why-foursquare-swarm-is-still-my-favourite-social-network-e38228493e6c,Why Foursquare / Swarm is still my favourite social network,,Starred
https://www.20minutes.fr/high-tech/2077615-20170531-quoi-exactement-tweet-covfefe-donald-trump-persiste-signe,"Dis donc Donald Trump, c'est quoi exactement «covfefe»?",,test_tag

1 URL Title Selection Folder
2 https://www.liberation.fr/societe/2012/12/06/baumettes-un-tour-en-cellule_865551 http://www.liberation.fr/societe/2012/12/06/baumettes-un-tour-en-cellule_865551 Baumettes : un tour en cellule Unread
3 https://redditblog.com/2016/09/20/amp-and-reactredux/ AMP and React+Redux: Why Not? Archive
4 https://medium.com/@the_minh/why-foursquare-swarm-is-still-my-favourite-social-network-e38228493e6c Why Foursquare / Swarm is still my favourite social network Starred
5 https://www.20minutes.fr/high-tech/2077615-20170531-quoi-exactement-tweet-covfefe-donald-trump-persiste-signe Dis donc Donald Trump, c'est quoi exactement «covfefe»? test_tag

View File

@ -21,7 +21,7 @@
{
"id": 22,
"title": "Réfugiés: l'UE va créer 100 000 places d'accueil dans les Balkans",
"url": "https://www.liberation.fr/planete/2015/10/26/refugies-l-ue-va-creer-100-000-places-d-accueil-dans-les-balkans_1408867",
"url": "http://www.liberation.fr/planete/2015/10/26/refugies-l-ue-va-creer-100-000-places-d-accueil-dans-les-balkans_1408867",
"is_archived": false,
"created_at": "2016-09-08T11:55:58+0200",
"updated_at": "2016-09-08T11:57:16+0200",

View File

@ -1,48 +0,0 @@
{
"short_name": "wallabag",
"name": "Save and classify articles. Read them later. Freely.",
"icons": [
{
"src": "wallassets/themes/_global/img/appicon/apple-touch-icon-57.png",
"type": "image/png",
"sizes": "57x57"
},
{
"src": "wallassets/themes/_global/img/appicon/apple-touch-icon-72.png",
"type": "image/png",
"sizes": "72x72"
},
{
"src": "wallassets/themes/_global/img/appicon/apple-touch-icon-76.png",
"type": "image/png",
"sizes": "76x76"
},
{
"src": "wallassets/themes/_global/img/appicon/apple-touch-icon-114.png",
"type": "image/png",
"sizes": "114x114"
},
{
"src": "wallassets/themes/_global/img/appicon/apple-touch-icon-120.png",
"type": "image/png",
"sizes": "120x120"
},
{
"src": "wallassets/themes/_global/img/appicon/apple-touch-icon-144.png",
"type": "image/png",
"sizes": "144x144"
},
{
"src": "wallassets/themes/_global/img/appicon/apple-touch-icon-152.png",
"type": "image/png",
"sizes": "152x152"
},
{
"src": "wallassets/themes/_global/img/appicon/apple-touch-icon-512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"display": "standalone",
"background_color": "#FFFFFF"
}

File diff suppressed because one or more lines are too long

View File

@ -80,7 +80,8 @@
"themes/_global/img/icons/shaarli.png": "themes/_global/img/icons/shaarli.png",
"themes/_global/img/icons/unmark-icon--black.png": "themes/_global/img/icons/unmark-icon--black.png",
"themes/_global/img/list.png": "themes/_global/img/list.png",
"themes/_global/img/logo-square.svg": "themes/_global/img/logo-square.svg",
"themes/_global/img/logo-other_themes.png": "themes/_global/img/logo-other_themes.png",
"themes/_global/img/logo-square.png": "themes/_global/img/logo-square.png",
"themes/_global/img/logo-w.png": "themes/_global/img/logo-w.png",
"themes/_global/img/logo-wallabag.svg": "themes/_global/img/logo-wallabag.svg",
"themes/_global/img/table.png": "themes/_global/img/table.png"

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More