Automatically downscale pictures to reduce page loading times (closes #275)

This commit is contained in:
Bernd Bestel 2019-09-18 11:04:59 +02:00
parent ba089a3d79
commit d209c0bd22
No known key found for this signature in database
GPG Key ID: 71BD34C0D4891300
11 changed files with 314 additions and 173 deletions

View File

@ -35,12 +35,14 @@
### General improvements/fixes
- Improved the handling which entry page to use with disabled feature flags (thanks @nielstholenaar)
- Boolean settings provided via environment variables (so the strings `true` and `false`) are now parsed correctly (thanks @mduret)
- All uploaded pictures (currently for products and recipes) are now automatically downscaled to the appropriate size when serving them to improve page load times
### API improvements & non-breaking changes
- New endpoint `/stock/shoppinglist/add-product` to add a product to a shopping list (thanks @Forceu)
- New endpoint `/stock/shoppinglist/remove-product` to remove a product from a shopping list (thanks @Forceu)
- New endpoint `/chores/executions/calculate-next-assignments` to (re)calculate next user assignments for a single or all chores
- New endpoint `/objects/{entity}/search/{searchString}` search for objects by name (contains search)
- Endpoint `GET /files/{group}/{fileName}` can now also downscale pictures (see API documentation on [/api](https://demo-en.grocy.info/api))
- When adding a product (through `stock/product/{productId}/add` or `stock/product/{productId}/inventory`) with omitted best before date and if the given product has "Default best before days" set, the best before date is calculated based on that (so far always today was used which is still the case when no date is supplied and also the product has no "Default best before days set) (thanks @Forceu)
- Field `stock_amount` of endpoint `/stock/products/{productId}´ now returns `0` instead of `null` when the given product is not in stock (thanks @Forceu)
- Fixed that `/system/db-changed-time` always returned the current time (more or less) due to that that time is the database file modification time and the database is effectively changed on each request because of session information tracking - which now explicitly does not change the database file modification time, so this should work again to determine if any data changes happened

View File

@ -7,7 +7,8 @@
"tuupola/cors-middleware": "^0.9.4",
"eluceo/ical": "^0.15.0",
"erusev/parsedown": "^1.7.3",
"gettext/gettext": "^4.6.2"
"gettext/gettext": "^4.6.2",
"gumlet/php-image-resize": "^1.9.2"
},
"autoload": {
"psr-4": {

380
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "613590bc6e46e2b4542023617bd56778",
"content-hash": "17eb560bc9d67d2f79118929ae59ca34",
"packages": [
{
"name": "container-interop/container-interop",
@ -106,16 +106,16 @@
},
{
"name": "eluceo/ical",
"version": "0.15.0",
"version": "0.15.1",
"source": {
"type": "git",
"url": "https://github.com/markuspoerschke/iCal.git",
"reference": "add0ca99aa1f77f134a2e8b071f2ebc22b115139"
"reference": "bdd24747587f6f9b10770a7b873a13e273f85f39"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/markuspoerschke/iCal/zipball/add0ca99aa1f77f134a2e8b071f2ebc22b115139",
"reference": "add0ca99aa1f77f134a2e8b071f2ebc22b115139",
"url": "https://api.github.com/repos/markuspoerschke/iCal/zipball/bdd24747587f6f9b10770a7b873a13e273f85f39",
"reference": "bdd24747587f6f9b10770a7b873a13e273f85f39",
"shasum": ""
},
"require": {
@ -153,7 +153,7 @@
"ics",
"php calendar"
],
"time": "2019-01-13T22:00:58+00:00"
"time": "2019-08-06T20:33:43+00:00"
},
{
"name": "erusev/parsedown",
@ -203,16 +203,16 @@
},
{
"name": "gettext/gettext",
"version": "v4.6.2",
"version": "v4.6.3",
"source": {
"type": "git",
"url": "https://github.com/oscarotero/Gettext.git",
"reference": "93176b272d61fb58a9767be71c50d19149cb1e48"
"reference": "70c6ff2fecd275e6ef9cdd542f55939a3d1904d6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/oscarotero/Gettext/zipball/93176b272d61fb58a9767be71c50d19149cb1e48",
"reference": "93176b272d61fb58a9767be71c50d19149cb1e48",
"url": "https://api.github.com/repos/oscarotero/Gettext/zipball/70c6ff2fecd275e6ef9cdd542f55939a3d1904d6",
"reference": "70c6ff2fecd275e6ef9cdd542f55939a3d1904d6",
"shasum": ""
},
"require": {
@ -261,7 +261,7 @@
"po",
"translation"
],
"time": "2019-01-12T18:40:56+00:00"
"time": "2019-07-15T12:56:31+00:00"
},
{
"name": "gettext/languages",
@ -325,17 +325,72 @@
"time": "2018-11-13T22:06:07+00:00"
},
{
"name": "illuminate/container",
"version": "v5.8.15",
"name": "gumlet/php-image-resize",
"version": "1.9.2",
"source": {
"type": "git",
"url": "https://github.com/illuminate/container.git",
"reference": "9405989993a48c2cd50ad1e5b2b08a33383c3807"
"url": "https://github.com/gumlet/php-image-resize.git",
"reference": "06339a9c1b167acd58173db226f57957a6617547"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/container/zipball/9405989993a48c2cd50ad1e5b2b08a33383c3807",
"reference": "9405989993a48c2cd50ad1e5b2b08a33383c3807",
"url": "https://api.github.com/repos/gumlet/php-image-resize/zipball/06339a9c1b167acd58173db226f57957a6617547",
"reference": "06339a9c1b167acd58173db226f57957a6617547",
"shasum": ""
},
"require": {
"ext-fileinfo": "*",
"ext-gd": "*",
"php": ">=5.5.0"
},
"require-dev": {
"apigen/apigen": "^4.1",
"ext-exif": "*",
"ext-gd": "*",
"php-coveralls/php-coveralls": "^2.1",
"phpunit/phpunit": "^4.8"
},
"suggest": {
"ext-exif": "Auto-rotate jpeg files"
},
"type": "library",
"autoload": {
"psr-4": {
"Gumlet\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Aditya Patadia",
"homepage": "http://aditya.patadia.org/"
}
],
"description": "PHP class to re-size and scale images",
"homepage": "https://github.com/gumlet/php-image-resize",
"keywords": [
"image",
"php",
"resize",
"scale"
],
"time": "2019-01-01T13:53:00+00:00"
},
{
"name": "illuminate/container",
"version": "v5.8.35",
"source": {
"type": "git",
"url": "https://github.com/illuminate/container.git",
"reference": "b42e5ef939144b77f78130918da0ce2d9ee16574"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/container/zipball/b42e5ef939144b77f78130918da0ce2d9ee16574",
"reference": "b42e5ef939144b77f78130918da0ce2d9ee16574",
"shasum": ""
},
"require": {
@ -367,20 +422,20 @@
],
"description": "The Illuminate Container package.",
"homepage": "https://laravel.com",
"time": "2019-04-22T13:12:35+00:00"
"time": "2019-08-20T02:00:23+00:00"
},
{
"name": "illuminate/contracts",
"version": "v5.8.15",
"version": "v5.8.35",
"source": {
"type": "git",
"url": "https://github.com/illuminate/contracts.git",
"reference": "0b3cbe19051c9a8c247091cc0867d3b65250d093"
"reference": "00fc6afee788fa07c311b0650ad276585f8aef96"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/contracts/zipball/0b3cbe19051c9a8c247091cc0867d3b65250d093",
"reference": "0b3cbe19051c9a8c247091cc0867d3b65250d093",
"url": "https://api.github.com/repos/illuminate/contracts/zipball/00fc6afee788fa07c311b0650ad276585f8aef96",
"reference": "00fc6afee788fa07c311b0650ad276585f8aef96",
"shasum": ""
},
"require": {
@ -411,11 +466,11 @@
],
"description": "The Illuminate Contracts package.",
"homepage": "https://laravel.com",
"time": "2019-04-21T18:51:09+00:00"
"time": "2019-07-30T13:57:21+00:00"
},
{
"name": "illuminate/events",
"version": "v5.8.15",
"version": "v5.8.35",
"source": {
"type": "git",
"url": "https://github.com/illuminate/events.git",
@ -460,16 +515,16 @@
},
{
"name": "illuminate/filesystem",
"version": "v5.8.15",
"version": "v5.8.35",
"source": {
"type": "git",
"url": "https://github.com/illuminate/filesystem.git",
"reference": "e3c7302b147704420041c07aac538b9de67ebb8f"
"reference": "494ba903402d64ec49c8d869ab61791db34b2288"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/filesystem/zipball/e3c7302b147704420041c07aac538b9de67ebb8f",
"reference": "e3c7302b147704420041c07aac538b9de67ebb8f",
"url": "https://api.github.com/repos/illuminate/filesystem/zipball/494ba903402d64ec49c8d869ab61791db34b2288",
"reference": "494ba903402d64ec49c8d869ab61791db34b2288",
"shasum": ""
},
"require": {
@ -508,20 +563,20 @@
],
"description": "The Illuminate Filesystem package.",
"homepage": "https://laravel.com",
"time": "2019-04-08T12:56:11+00:00"
"time": "2019-08-14T13:38:15+00:00"
},
{
"name": "illuminate/support",
"version": "v5.8.15",
"version": "v5.8.35",
"source": {
"type": "git",
"url": "https://github.com/illuminate/support.git",
"reference": "7fbf8d76946ee53587955b670bd8a47e3d48e854"
"reference": "e63a495d3bf01654f70def1046fb925c4bb56506"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/support/zipball/7fbf8d76946ee53587955b670bd8a47e3d48e854",
"reference": "7fbf8d76946ee53587955b670bd8a47e3d48e854",
"url": "https://api.github.com/repos/illuminate/support/zipball/e63a495d3bf01654f70def1046fb925c4bb56506",
"reference": "e63a495d3bf01654f70def1046fb925c4bb56506",
"shasum": ""
},
"require": {
@ -569,20 +624,20 @@
],
"description": "The Illuminate Support package.",
"homepage": "https://laravel.com",
"time": "2019-04-25T14:06:24+00:00"
"time": "2019-09-03T16:36:47+00:00"
},
{
"name": "illuminate/view",
"version": "v5.8.15",
"version": "v5.8.35",
"source": {
"type": "git",
"url": "https://github.com/illuminate/view.git",
"reference": "a62ef6b6c4392a8bb5cf3af5f5076459525286c5"
"reference": "c859919bc3be97a3f114377d5d812f047b8ea90d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/view/zipball/a62ef6b6c4392a8bb5cf3af5f5076459525286c5",
"reference": "a62ef6b6c4392a8bb5cf3af5f5076459525286c5",
"url": "https://api.github.com/repos/illuminate/view/zipball/c859919bc3be97a3f114377d5d812f047b8ea90d",
"reference": "c859919bc3be97a3f114377d5d812f047b8ea90d",
"shasum": ""
},
"require": {
@ -618,7 +673,7 @@
],
"description": "The Illuminate View package.",
"homepage": "https://laravel.com",
"time": "2019-04-17T14:14:38+00:00"
"time": "2019-06-20T13:13:59+00:00"
},
{
"name": "morris/lessql",
@ -726,16 +781,16 @@
},
{
"name": "nesbot/carbon",
"version": "2.17.1",
"version": "2.24.0",
"source": {
"type": "git",
"url": "https://github.com/briannesbitt/Carbon.git",
"reference": "96acbc0c03782e8115156dd4dd8b736267155066"
"reference": "934459c5ac0658bc765ad1e53512c7c77adcac29"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/96acbc0c03782e8115156dd4dd8b736267155066",
"reference": "96acbc0c03782e8115156dd4dd8b736267155066",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/934459c5ac0658bc765ad1e53512c7c77adcac29",
"reference": "934459c5ac0658bc765ad1e53512c7c77adcac29",
"shasum": ""
},
"require": {
@ -746,11 +801,14 @@
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.14 || ^3.0",
"kylekatarnls/multi-tester": "^1.1",
"phpmd/phpmd": "^2.6",
"phpmd/phpmd": "dev-php-7.1-compatibility",
"phpstan/phpstan": "^0.11",
"phpunit/phpunit": "^7.5 || ^8.0",
"squizlabs/php_codesniffer": "^3.4"
},
"bin": [
"bin/carbon"
],
"type": "library",
"extra": {
"laravel": {
@ -773,16 +831,20 @@
"name": "Brian Nesbitt",
"email": "brian@nesbot.com",
"homepage": "http://nesbot.com"
},
{
"name": "kylekatarnls",
"homepage": "http://github.com/kylekatarnls"
}
],
"description": "A simple API extension for DateTime.",
"description": "A API extension for DateTime that supports 281 different languages.",
"homepage": "http://carbon.nesbot.com",
"keywords": [
"date",
"datetime",
"time"
],
"time": "2019-04-27T18:04:27+00:00"
"time": "2019-08-31T16:37:55+00:00"
},
{
"name": "nikic/fast-route",
@ -1325,20 +1387,23 @@
},
{
"name": "slim/slim",
"version": "3.12.1",
"version": "3.12.2",
"source": {
"type": "git",
"url": "https://github.com/slimphp/Slim.git",
"reference": "eaee12ef8d0750db62b8c548016d82fb33addb6b"
"reference": "200c6143f15baa477601879b64ab2326847aac0b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/slimphp/Slim/zipball/eaee12ef8d0750db62b8c548016d82fb33addb6b",
"reference": "eaee12ef8d0750db62b8c548016d82fb33addb6b",
"url": "https://api.github.com/repos/slimphp/Slim/zipball/200c6143f15baa477601879b64ab2326847aac0b",
"reference": "200c6143f15baa477601879b64ab2326847aac0b",
"shasum": ""
},
"require": {
"container-interop/container-interop": "^1.2",
"ext-json": "*",
"ext-libxml": "*",
"ext-simplexml": "*",
"nikic/fast-route": "^1.0",
"php": ">=5.5.0",
"pimple/pimple": "^3.0",
@ -1363,25 +1428,25 @@
"MIT"
],
"authors": [
{
"name": "Rob Allen",
"email": "rob@akrabat.com",
"homepage": "http://akrabat.com"
},
{
"name": "Josh Lockhart",
"email": "hello@joshlockhart.com",
"homepage": "https://joshlockhart.com"
},
{
"name": "Gabriel Manricks",
"email": "gmanricks@me.com",
"homepage": "http://gabrielmanricks.com"
},
{
"name": "Andrew Smith",
"email": "a.smith@silentworks.co.uk",
"homepage": "http://silentworks.co.uk"
},
{
"name": "Rob Allen",
"email": "rob@akrabat.com",
"homepage": "http://akrabat.com"
},
{
"name": "Gabriel Manricks",
"email": "gmanricks@me.com",
"homepage": "http://gabrielmanricks.com"
}
],
"description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
@ -1392,91 +1457,20 @@
"micro",
"router"
],
"time": "2019-04-16T16:47:29+00:00"
},
{
"name": "symfony/contracts",
"version": "v1.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/contracts.git",
"reference": "d3636025e8253c6144358ec0a62773cae588395b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/contracts/zipball/d3636025e8253c6144358ec0a62773cae588395b",
"reference": "d3636025e8253c6144358ec0a62773cae588395b",
"shasum": ""
},
"require": {
"php": "^7.1.3"
},
"require-dev": {
"psr/cache": "^1.0",
"psr/container": "^1.0",
"symfony/polyfill-intl-idn": "^1.10"
},
"suggest": {
"psr/cache": "When using the Cache contracts",
"psr/container": "When using the Service contracts",
"symfony/cache-contracts-implementation": "",
"symfony/event-dispatcher-implementation": "",
"symfony/http-client-contracts-implementation": "",
"symfony/service-contracts-implementation": "",
"symfony/translation-contracts-implementation": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\": ""
},
"exclude-from-classmap": [
"**/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "A set of abstractions extracted out of the Symfony components",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"time": "2019-04-27T14:29:50+00:00"
"time": "2019-08-20T18:46:05+00:00"
},
{
"name": "symfony/debug",
"version": "v4.2.8",
"version": "v4.3.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "2d279b6bb1d582dd5740d4d3251ae8c18812ed37"
"reference": "afcdea44a2e399c1e4b52246ec8d54c715393ced"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/2d279b6bb1d582dd5740d4d3251ae8c18812ed37",
"reference": "2d279b6bb1d582dd5740d4d3251ae8c18812ed37",
"url": "https://api.github.com/repos/symfony/debug/zipball/afcdea44a2e399c1e4b52246ec8d54c715393ced",
"reference": "afcdea44a2e399c1e4b52246ec8d54c715393ced",
"shasum": ""
},
"require": {
@ -1492,7 +1486,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.2-dev"
"dev-master": "4.3-dev"
}
},
"autoload": {
@ -1519,20 +1513,20 @@
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
"time": "2019-04-11T11:27:41+00:00"
"time": "2019-08-20T14:27:59+00:00"
},
{
"name": "symfony/finder",
"version": "v4.2.8",
"version": "v4.3.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "e45135658bd6c14b61850bf131c4f09a55133f69"
"reference": "86c1c929f0a4b24812e1eb109262fc3372c8e9f2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/e45135658bd6c14b61850bf131c4f09a55133f69",
"reference": "e45135658bd6c14b61850bf131c4f09a55133f69",
"url": "https://api.github.com/repos/symfony/finder/zipball/86c1c929f0a4b24812e1eb109262fc3372c8e9f2",
"reference": "86c1c929f0a4b24812e1eb109262fc3372c8e9f2",
"shasum": ""
},
"require": {
@ -1541,7 +1535,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.2-dev"
"dev-master": "4.3-dev"
}
},
"autoload": {
@ -1568,20 +1562,20 @@
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
"time": "2019-04-06T13:51:08+00:00"
"time": "2019-08-14T12:26:46+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.11.0",
"version": "v1.12.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "fe5e94c604826c35a32fa832f35bd036b6799609"
"reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fe5e94c604826c35a32fa832f35bd036b6799609",
"reference": "fe5e94c604826c35a32fa832f35bd036b6799609",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/b42a2f66e8f1b15ccf25652c3424265923eb4f17",
"reference": "b42a2f66e8f1b15ccf25652c3424265923eb4f17",
"shasum": ""
},
"require": {
@ -1593,7 +1587,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.11-dev"
"dev-master": "1.12-dev"
}
},
"autoload": {
@ -1627,26 +1621,26 @@
"portable",
"shim"
],
"time": "2019-02-06T07:57:58+00:00"
"time": "2019-08-06T08:03:45+00:00"
},
{
"name": "symfony/translation",
"version": "v4.2.8",
"version": "v4.3.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
"reference": "181a426dd129cb496f12d7e7555f6d0b37a7615b"
"reference": "28498169dd334095fa981827992f3a24d50fed0f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/181a426dd129cb496f12d7e7555f6d0b37a7615b",
"reference": "181a426dd129cb496f12d7e7555f6d0b37a7615b",
"url": "https://api.github.com/repos/symfony/translation/zipball/28498169dd334095fa981827992f3a24d50fed0f",
"reference": "28498169dd334095fa981827992f3a24d50fed0f",
"shasum": ""
},
"require": {
"php": "^7.1.3",
"symfony/contracts": "^1.0.2",
"symfony/polyfill-mbstring": "~1.0"
"symfony/polyfill-mbstring": "~1.0",
"symfony/translation-contracts": "^1.1.6"
},
"conflict": {
"symfony/config": "<3.4",
@ -1654,7 +1648,7 @@
"symfony/yaml": "<3.4"
},
"provide": {
"symfony/translation-contracts-implementation": "1.0"
"symfony/translation-implementation": "1.0"
},
"require-dev": {
"psr/log": "~1.0",
@ -1664,6 +1658,7 @@
"symfony/finder": "~2.8|~3.0|~4.0",
"symfony/http-kernel": "~3.4|~4.0",
"symfony/intl": "~3.4|~4.0",
"symfony/service-contracts": "^1.1.2",
"symfony/var-dumper": "~3.4|~4.0",
"symfony/yaml": "~3.4|~4.0"
},
@ -1675,7 +1670,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.2-dev"
"dev-master": "4.3-dev"
}
},
"autoload": {
@ -1702,7 +1697,64 @@
],
"description": "Symfony Translation Component",
"homepage": "https://symfony.com",
"time": "2019-05-01T12:55:36+00:00"
"time": "2019-08-26T08:55:16+00:00"
},
{
"name": "symfony/translation-contracts",
"version": "v1.1.6",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation-contracts.git",
"reference": "325b17c24f3ee23cbecfa63ba809c6d89b5fa04a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/325b17c24f3ee23cbecfa63ba809c6d89b5fa04a",
"reference": "325b17c24f3ee23cbecfa63ba809c6d89b5fa04a",
"shasum": ""
},
"require": {
"php": "^7.1.3"
},
"suggest": {
"symfony/translation-implementation": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Contracts\\Translation\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Generic abstractions related to translation",
"homepage": "https://symfony.com",
"keywords": [
"abstractions",
"contracts",
"decoupling",
"interfaces",
"interoperability",
"standards"
],
"time": "2019-08-02T12:15:04+00:00"
},
{
"name": "tuupola/callable-handler",
@ -1818,16 +1870,16 @@
},
{
"name": "tuupola/http-factory",
"version": "1.0.3",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/tuupola/http-factory.git",
"reference": "1fd4eaafe3a6e0c26d288e3b3e17d777ea1991bf"
"reference": "5fbde4c65a10d09a85652684a6e569542265a749"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tuupola/http-factory/zipball/1fd4eaafe3a6e0c26d288e3b3e17d777ea1991bf",
"reference": "1fd4eaafe3a6e0c26d288e3b3e17d777ea1991bf",
"url": "https://api.github.com/repos/tuupola/http-factory/zipball/5fbde4c65a10d09a85652684a6e569542265a749",
"reference": "5fbde4c65a10d09a85652684a6e569542265a749",
"shasum": ""
},
"require": {
@ -1871,7 +1923,7 @@
"psr-17",
"psr-7"
],
"time": "2019-01-11T15:13:01+00:00"
"time": "2019-08-07T07:10:58+00:00"
}
],
"packages-dev": [],

View File

@ -51,7 +51,32 @@ class FilesApiController extends BaseApiController
throw new \Exception('Invalid filename');
}
$forceServeAs = null;
if (isset($request->getQueryParams()['force_serve_as']) && !empty($request->getQueryParams()['force_serve_as']))
{
$forceServeAs = $request->getQueryParams()['force_serve_as'];
}
if ($forceServeAs == FilesService::FILE_SERVE_TYPE_PICTURE)
{
$bestFitHeight = 999999;
if (isset($request->getQueryParams()['best_fit_height']) && !empty($request->getQueryParams()['best_fit_height']) && is_numeric($request->getQueryParams()['best_fit_height']))
{
$bestFitHeight = $request->getQueryParams()['best_fit_height'];
}
$bestFitWidth = 999999;
if (isset($request->getQueryParams()['best_fit_width']) && !empty($request->getQueryParams()['best_fit_width']) && is_numeric($request->getQueryParams()['best_fit_width']))
{
$bestFitWidth = $request->getQueryParams()['best_fit_width'];
}
$filePath = $this->FilesService->DownscaleImage($args['group'], $fileName, $bestFitHeight, $bestFitWidth);
}
else
{
$filePath = $this->FilesService->GetFilePath($args['group'], $fileName);
}
if (file_exists($filePath))
{

View File

@ -655,6 +655,37 @@
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "force_serve_as",
"required": false,
"description": "Force the file to be served as the given type",
"schema": {
"type": "string",
"enum": [
"picture"
]
}
},
{
"in": "query",
"name": "best_fit_height",
"required": false,
"description": "Only when using `force_serve_as` = `picture`: Downscale the picture to the given height while maintaining the aspect ratio",
"schema": {
"type": "integer"
}
}
,
{
"in": "query",
"name": "best_fit_width",
"required": false,
"description": "Only when using `force_serve_as` = `picture`: Downscale the picture to the given width while maintaining the aspect ratio",
"schema": {
"type": "integer"
}
}
],
"responses": {

View File

@ -82,7 +82,7 @@ Grocy.Components.ProductCard.Refresh = function(productId)
{
$("#productcard-no-product-picture").addClass("d-none");
$("#productcard-product-picture").removeClass("d-none");
$("#productcard-product-picture").attr("src", U('/api/files/productpictures/' + btoa(productDetails.product.picture_file_name)));
$("#productcard-product-picture").attr("src", U('/api/files/productpictures/' + btoa(productDetails.product.picture_file_name) + '?force_serve_as=picture&best_fit_height=400&best_fit_width=400'));
}
else
{

View File

@ -103,7 +103,7 @@ var calendar = $("#calendar").fullCalendar({
if (recipe.picture_file_name && !recipe.picture_file_name.isEmpty())
{
element.html(element.html() + '<img src="' + U("/api/files/recipepictures/") + btoa(recipe.picture_file_name) + '" class="img-fluid">')
element.html(element.html() + '<img src="' + U("/api/files/recipepictures/") + btoa(recipe.picture_file_name) + '?force_serve_as=picture&best_fit_height=400&best_fit_width=400" class="img-fluid">')
}
},
"eventAfterAllRender": function(view)

View File

@ -2,8 +2,12 @@
namespace Grocy\Services;
use \Gumlet\ImageResize;
class FilesService extends BaseService
{
const FILE_SERVE_TYPE_PICTURE = 'picture';
public function __construct()
{
parent::__construct();
@ -28,4 +32,30 @@ class FilesService extends BaseService
return $groupFolderPath . '/' . $fileName;
}
public function DownscaleImage($group, $fileName, $bestFitHeight, $bestFitWidth)
{
$filePath = $this->GetFilePath($group, $fileName);
$fileNameWithoutExtension = pathinfo($filePath, PATHINFO_FILENAME);
$fileExtension = pathinfo($filePath, PATHINFO_EXTENSION);
$fileNameDownscaled = $fileNameWithoutExtension . '__downscaledto' . $bestFitHeight . 'x' . $bestFitWidth . '.' . $fileExtension;
$filePathDownscaled = $this->GetFilePath($group, $fileNameDownscaled);
try
{
if (!file_exists($filePathDownscaled))
{
$image = new ImageResize($filePath);
$image->resizeToBestFit($bestFitHeight, $bestFitWidth);
$image->save($filePathDownscaled);
}
}
catch (ImageResizeException $ex)
{
return $filePath;
}
return $filePathDownscaled;
}
}

View File

@ -275,7 +275,7 @@
<label class="mt-2">{{ $__t('Picture') }}</label>
<button id="delete-current-product-picture-button" class="btn btn-sm btn-danger @if(empty($product->picture_file_name)) disabled @endif"><i class="fas fa-trash"></i> {{ $__t('Delete') }}</button>
@if(!empty($product->picture_file_name))
<p><img id="current-product-picture" src="{{ $U('/api/files/productpictures/' . base64_encode($product->picture_file_name)) }}" class="img-fluid img-thumbnail mt-2"></p>
<p><img id="current-product-picture" src="{{ $U('/api/files/productpictures/' . base64_encode($product->picture_file_name) . '?force_serve_as=picture&best_fit_height=400&best_fit_width=400') }}" class="img-fluid img-thumbnail mt-2"></p>
<p id="delete-current-product-picture-on-save-hint" class="form-text text-muted font-italic d-none">{{ $__t('The current picture will be deleted when you save the product') }}</p>
@else
<p id="no-current-product-picture-hint" class="form-text text-muted font-italic">{{ $__t('No picture available') }}</p>

View File

@ -209,7 +209,7 @@
<label class="mt-2">{{ $__t('Picture') }}</label>
<button id="delete-current-recipe-picture-button" class="btn btn-sm btn-danger @if(empty($recipe->picture_file_name)) disabled @endif"><i class="fas fa-trash"></i> {{ $__t('Delete') }}</button>
@if(!empty($recipe->picture_file_name))
<p><img id="current-recipe-picture" src="{{ $U('/api/files/recipepictures/' . base64_encode($recipe->picture_file_name)) }}" class="img-fluid img-thumbnail mt-2"></p>
<p><img id="current-recipe-picture" src="{{ $U('/api/files/recipepictures/' . base64_encode($recipe->picture_file_name) . '?force_serve_as=picture&best_fit_height=400&best_fit_width=400') }}" class="img-fluid img-thumbnail mt-2"></p>
<p id="delete-current-recipe-picture-on-save-hint" class="form-text text-muted font-italic d-none">{{ $__t('The current picture will be deleted when you save the recipe') }}</p>
@else
<p id="no-current-recipe-picture-hint" class="form-text text-muted font-italic">{{ $__t('No picture available') }}</p>

View File

@ -102,7 +102,7 @@
<a class="discrete-link recipe-gallery-item" data-recipe-id="{{ $recipe->id }}" href="#">
<div id="recipe-card-{{ $recipe->id }}" class="card border-white mb-0 recipe-card">
@if(!empty($recipe->picture_file_name))
<img src="{{ $U('/api/files/recipepictures/' . base64_encode($recipe->picture_file_name)) }}" class="img-fluid">
<img src="{{ $U('/api/files/recipepictures/' . base64_encode($recipe->picture_file_name) . '?force_serve_as=picture&best_fit_height=400&best_fit_width=400') }}" class="img-fluid">
@endif
<div class="card-body text-center">
<h5 class="card-title mb-1">{{ $recipe->name }}</h5>
@ -173,7 +173,7 @@
</div>
@if(!empty($selectedRecipeSubRecipe->picture_file_name))
<p class="w-75 mx-auto"><img src="{{ $U('/api/files/recipepictures/' . base64_encode($selectedRecipeSubRecipe->picture_file_name)) }}" class="img-fluid img-thumbnail"></p>
<p class="w-75 mx-auto txt-center"><img src="{{ $U('/api/files/recipepictures/' . base64_encode($selectedRecipeSubRecipe->picture_file_name) . '?force_serve_as=picture&best_fit_height=400&best_fit_width=400') }}" class="img-fluid img-thumbnail"></p>
@endif
@php $selectedRecipeSubRecipePositionsFiltered = FindAllObjectsInArrayByPropertyValue($selectedRecipeSubRecipesPositions, 'child_recipe_id', $selectedRecipeSubRecipe->id); @endphp
@ -225,7 +225,7 @@
<!-- Selected recipe -->
@if(!empty($selectedRecipe->picture_file_name))
<p class="w-75 mx-auto"><img src="{{ $U('/api/files/recipepictures/' . base64_encode($selectedRecipe->picture_file_name)) }}" class="img-fluid img-thumbnail"></p>
<p class="w-75 mx-auto text-center"><img src="{{ $U('/api/files/recipepictures/' . base64_encode($selectedRecipe->picture_file_name) . '?force_serve_as=picture&best_fit_height=400&best_fit_width=400') }}" class="img-fluid img-thumbnail"></p>
@endif
@if($selectedRecipePositionsResolved->count() > 0)