diff --git a/README.md b/README.md index 3015fbf2..b16dc023 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@
-Logo +Logo

ERP beyond your fridge

-
grocy is a web-based self-hosted groceries & household management solution for your home
+

grocy is a web-based self-hosted groceries & household management solution for your home
Created by @berrnd

----- diff --git a/changelog/62_UNRELEASED_xxxx-xx-xx.md b/changelog/62_3.1.0_2021-07-16.md similarity index 98% rename from changelog/62_UNRELEASED_xxxx-xx-xx.md rename to changelog/62_3.1.0_2021-07-16.md index 0edbdc9f..6703f6e4 100644 --- a/changelog/62_UNRELEASED_xxxx-xx-xx.md +++ b/changelog/62_3.1.0_2021-07-16.md @@ -2,7 +2,7 @@ > ⚠️ PHP 8 is now supported and from now on the only tested runtime version (although currently PHP 7.2 should still work). -### New feature: grocycode +### New feature: grocycode / label printer support #### (Own) Product/stock entry/chores/batteries labels/barcodes - Print own labels/barcodes for products/stock entries/chores/batteries and then scan that code on every place a product/stock entry/chore/battery can be selected - Can be printed (or downloaded) via @@ -16,8 +16,8 @@ - Label printer communication happens via WebHooks - see the new `LABEL_PRINTER*` `config.php` options - grocycodes can also be used without a label printer - you can view or download thm as pictures and print them manually - More information: - - https://github.com/grocy/grocy/blob/master/docs/grocycode.md - - https://github.com/grocy/grocy/blob/master/docs/label-printing.md + - https://github.com/grocy/grocy/tree/v3.1.0/docs/grocycode.md + - https://github.com/grocy/grocy/tree/v3.1.0/docs/label-printing.md - (Thanks a lot @mistressofjellyfish for the initial work on this) ### New feature: Meal plan sections diff --git a/config-dist.php b/config-dist.php index 15b8cff3..dc654736 100644 --- a/config-dist.php +++ b/config-dist.php @@ -175,9 +175,8 @@ DefaultUserSetting('batteries_due_soon_days', 5); // Tasks settings DefaultUserSetting('tasks_due_soon_days', 5); -// If the page should be automatically reloaded when there was -// an external change -DefaultUserSetting('auto_reload_on_db_change', true); +// If the page should be automatically reloaded when there was an external change +DefaultUserSetting('auto_reload_on_db_change', false); // Show a clock in the header next to the logo or not DefaultUserSetting('show_clock_in_header', false); diff --git a/controllers/BaseApiController.php b/controllers/BaseApiController.php index 96a2d343..7fecc207 100644 --- a/controllers/BaseApiController.php +++ b/controllers/BaseApiController.php @@ -6,18 +6,13 @@ use LessQL\Result; class BaseApiController extends BaseController { - protected $OpenApiSpec = null; - const PATTERN_FIELD = '[A-Za-z_][A-Za-z0-9_]+'; const PATTERN_OPERATOR = '!?(=|~|<|>|(>=)|(<=)|(§))'; const PATTERN_VALUE = '[A-Za-z\x{0400}-\x{04FF}_0-9.$#^|-]+'; - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } + protected $OpenApiSpec = null; protected function ApiResponse(\Psr\Http\Message\ResponseInterface $response, $data, $cache = false) { diff --git a/controllers/BaseController.php b/controllers/BaseController.php index 7d76c23b..9d14e15d 100644 --- a/controllers/BaseController.php +++ b/controllers/BaseController.php @@ -21,14 +21,14 @@ use Grocy\Services\UsersService; class BaseController { - protected $AppContainer; - public function __construct(\DI\Container $container) { $this->AppContainer = $container; $this->View = $container->get('view'); } + protected $AppContainer; + protected function getApiKeyService() { return ApiKeyService::getInstance(); diff --git a/controllers/BatteriesApiController.php b/controllers/BatteriesApiController.php index 5640d78e..fa054085 100644 --- a/controllers/BatteriesApiController.php +++ b/controllers/BatteriesApiController.php @@ -34,7 +34,6 @@ class BatteriesApiController extends BaseApiController try { $trackedTime = date('Y-m-d H:i:s'); - if (array_key_exists('tracked_time', $requestBody) && IsIsoDateTime($requestBody['tracked_time'])) { $trackedTime = $requestBody['tracked_time']; @@ -87,9 +86,4 @@ class BatteriesApiController extends BaseApiController return $this->GenericErrorResponse($response, $ex->getMessage()); } } - - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } } diff --git a/controllers/BatteriesController.php b/controllers/BatteriesController.php index 7b413a50..95d7441b 100644 --- a/controllers/BatteriesController.php +++ b/controllers/BatteriesController.php @@ -3,11 +3,11 @@ namespace Grocy\Controllers; use Grocy\Helpers\Grocycode; -use jucksearm\barcode\lib\BarcodeFactory; -use jucksearm\barcode\lib\DatamatrixFactory; class BatteriesController extends BaseController { + use GrocycodeTrait; + public function BatteriesList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { if (isset($request->getQueryParams()['include_disabled'])) @@ -98,40 +98,7 @@ class BatteriesController extends BaseController public function BatteryGrocycodeImage(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - $size = $request->getQueryParam('size', null); $gc = new Grocycode(Grocycode::BATTERY, $args['batteryId']); - - if (GROCY_GROCYCODE_TYPE == '2D') - { - $png = (new DatamatrixFactory())->setCode((string) $gc)->setSize($size)->getDatamatrixPngData(); - } - else - { - $png = (new BarcodeFactory())->setType('C128')->setCode((string) $gc)->setHeight($size)->getBarcodePngData(); - } - - $isDownload = $request->getQueryParam('download', false); - if ($isDownload) - { - $response = $response->withHeader('Content-Type', 'application/octet-stream') - ->withHeader('Content-Disposition', 'attachment; filename=grocycode.png') - ->withHeader('Content-Length', strlen($png)) - ->withHeader('Cache-Control', 'no-cache') - ->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT'); - } - else - { - $response = $response->withHeader('Content-Type', 'image/png') - ->withHeader('Content-Length', strlen($png)) - ->withHeader('Cache-Control', 'no-cache') - ->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT'); - } - $response->getBody()->write($png); - return $response; - } - - public function __construct(\DI\Container $container) - { - parent::__construct($container); + return $this->ServeGrocycodeImage($request, $response, $gc); } } diff --git a/controllers/CalendarApiController.php b/controllers/CalendarApiController.php index 8d3db47e..3c48d732 100644 --- a/controllers/CalendarApiController.php +++ b/controllers/CalendarApiController.php @@ -72,9 +72,4 @@ class CalendarApiController extends BaseApiController return $this->GenericErrorResponse($response, $ex->getMessage()); } } - - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } } diff --git a/controllers/CalendarController.php b/controllers/CalendarController.php index 1eb88282..a2ce556e 100644 --- a/controllers/CalendarController.php +++ b/controllers/CalendarController.php @@ -10,9 +10,4 @@ class CalendarController extends BaseController 'fullcalendarEventSources' => $this->getCalendarService()->GetEvents() ]); } - - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } } diff --git a/controllers/ChoresApiController.php b/controllers/ChoresApiController.php index f782977d..6994602f 100644 --- a/controllers/ChoresApiController.php +++ b/controllers/ChoresApiController.php @@ -68,14 +68,12 @@ class ChoresApiController extends BaseApiController User::checkPermission($request, User::PERMISSION_CHORE_TRACK_EXECUTION); $trackedTime = date('Y-m-d H:i:s'); - if (array_key_exists('tracked_time', $requestBody) && (IsIsoDateTime($requestBody['tracked_time']) || IsIsoDate($requestBody['tracked_time']))) { $trackedTime = $requestBody['tracked_time']; } $doneBy = GROCY_USER_ID; - if (array_key_exists('done_by', $requestBody) && !empty($requestBody['done_by'])) { $doneBy = $requestBody['done_by']; @@ -133,9 +131,4 @@ class ChoresApiController extends BaseApiController return $this->GenericErrorResponse($response, $ex->getMessage()); } } - - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } } diff --git a/controllers/ChoresController.php b/controllers/ChoresController.php index f2dd5803..d0f13a25 100644 --- a/controllers/ChoresController.php +++ b/controllers/ChoresController.php @@ -3,11 +3,11 @@ namespace Grocy\Controllers; use Grocy\Helpers\Grocycode; -use jucksearm\barcode\lib\BarcodeFactory; -use jucksearm\barcode\lib\DatamatrixFactory; class ChoresController extends BaseController { + use GrocycodeTrait; + public function ChoreEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { $usersService = $this->getUsersService(); @@ -115,40 +115,7 @@ class ChoresController extends BaseController public function ChoreGrocycodeImage(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - $size = $request->getQueryParam('size', null); $gc = new Grocycode(Grocycode::CHORE, $args['choreId']); - - if (GROCY_GROCYCODE_TYPE == '2D') - { - $png = (new DatamatrixFactory())->setCode((string) $gc)->setSize($size)->getDatamatrixPngData(); - } - else - { - $png = (new BarcodeFactory())->setType('C128')->setCode((string) $gc)->setHeight($size)->getBarcodePngData(); - } - - $isDownload = $request->getQueryParam('download', false); - if ($isDownload) - { - $response = $response->withHeader('Content-Type', 'application/octet-stream') - ->withHeader('Content-Disposition', 'attachment; filename=grocycode.png') - ->withHeader('Content-Length', strlen($png)) - ->withHeader('Cache-Control', 'no-cache') - ->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT'); - } - else - { - $response = $response->withHeader('Content-Type', 'image/png') - ->withHeader('Content-Length', strlen($png)) - ->withHeader('Cache-Control', 'no-cache') - ->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT'); - } - $response->getBody()->write($png); - return $response; - } - - public function __construct(\DI\Container $container) - { - parent::__construct($container); + return $this->ServeGrocycodeImage($request, $response, $gc); } } diff --git a/controllers/EquipmentController.php b/controllers/EquipmentController.php index e64db7c6..db14fca8 100644 --- a/controllers/EquipmentController.php +++ b/controllers/EquipmentController.php @@ -33,9 +33,4 @@ class EquipmentController extends BaseController 'userfieldValues' => $this->getUserfieldsService()->GetAllValues('equipment') ]); } - - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } } diff --git a/controllers/ExceptionController.php b/controllers/ExceptionController.php index cf21dc7c..84a3b2a8 100644 --- a/controllers/ExceptionController.php +++ b/controllers/ExceptionController.php @@ -11,17 +11,17 @@ use Throwable; class ExceptionController extends BaseApiController { - /** - * @var \Slim\App - */ - private $app; - public function __construct(\Slim\App $app, \DI\Container $container) { parent::__construct($container); $this->app = $app; } + /** + * @var \Slim\App + */ + private $app; + public function __invoke(ServerRequestInterface $request, Throwable $exception, bool $displayErrorDetails, bool $logErrors, bool $logErrorDetails, ?LoggerInterface $logger = null) { $response = $this->app->getResponseFactory()->createResponse(); @@ -59,7 +59,10 @@ class ExceptionController extends BaseApiController if ($exception instanceof HttpNotFoundException) { - define('GROCY_AUTHENTICATED', false); + if (!defined('GROCY_AUTHENTICATED')) + { + define('GROCY_AUTHENTICATED', false); + } return $this->renderPage($response->withStatus(404), 'errors/404', [ 'exception' => $exception diff --git a/controllers/FilesApiController.php b/controllers/FilesApiController.php index 5dbca1ec..45acfce8 100644 --- a/controllers/FilesApiController.php +++ b/controllers/FilesApiController.php @@ -118,11 +118,6 @@ class FilesApiController extends BaseApiController } } - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } - /** * @param string $fileName base64-encoded file-name * @return false|string the decoded file-name @@ -151,7 +146,6 @@ class FilesApiController extends BaseApiController protected function getFilePath(string $group, string $fileName, array $queryParams = []) { $forceServeAs = null; - if (isset($queryParams['force_serve_as']) && !empty($queryParams['force_serve_as'])) { $forceServeAs = $queryParams['force_serve_as']; @@ -160,14 +154,12 @@ class FilesApiController extends BaseApiController if ($forceServeAs == FilesService::FILE_SERVE_TYPE_PICTURE) { $bestFitHeight = null; - if (isset($queryParams['best_fit_height']) && !empty($queryParams['best_fit_height']) && is_numeric($queryParams['best_fit_height'])) { $bestFitHeight = $queryParams['best_fit_height']; } $bestFitWidth = null; - if (isset($queryParams['best_fit_width']) && !empty($queryParams['best_fit_width']) && is_numeric($queryParams['best_fit_width'])) { $bestFitWidth = $queryParams['best_fit_width']; diff --git a/controllers/GenericEntityApiController.php b/controllers/GenericEntityApiController.php index 7cb2d518..eb4b1e33 100644 --- a/controllers/GenericEntityApiController.php +++ b/controllers/GenericEntityApiController.php @@ -213,11 +213,6 @@ class GenericEntityApiController extends BaseApiController } } - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } - private function IsEntityWithEditRequiresAdmin($entity) { return in_array($entity, $this->getOpenApiSpec()->components->schemas->ExposedEntityEditRequiresAdmin->enum); diff --git a/controllers/GenericEntityController.php b/controllers/GenericEntityController.php index 7b18cb56..2a1b02fe 100644 --- a/controllers/GenericEntityController.php +++ b/controllers/GenericEntityController.php @@ -91,9 +91,4 @@ class GenericEntityController extends BaseController 'userfieldValues' => $this->getUserfieldsService()->GetAllValues('userentity-' . $args['userentityName']) ]); } - - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } } diff --git a/controllers/GrocycodeTrait.php b/controllers/GrocycodeTrait.php new file mode 100644 index 00000000..28453a44 --- /dev/null +++ b/controllers/GrocycodeTrait.php @@ -0,0 +1,45 @@ +getQueryParam('size', null); + + if (GROCY_GROCYCODE_TYPE == '2D') + { + $png = (new DatamatrixFactory())->setCode((string) $grocycode)->setSize($size)->getDatamatrixPngData(); + } + else + { + $png = (new BarcodeFactory())->setType('C128')->setCode((string) $grocycode)->setHeight($size)->getBarcodePngData(); + } + + $isDownload = $request->getQueryParam('download', false); + if ($isDownload) + { + $response = $response->withHeader('Content-Type', 'application/octet-stream') + ->withHeader('Content-Disposition', 'attachment; filename=grocycode.png') + ->withHeader('Content-Length', strlen($png)) + ->withHeader('Cache-Control', 'no-cache') + ->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT'); + } + else + { + $response = $response->withHeader('Content-Type', 'image/png') + ->withHeader('Content-Length', strlen($png)) + ->withHeader('Cache-Control', 'no-cache') + ->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT'); + } + $response->getBody()->write($png); + return $response; + } +} diff --git a/controllers/LoginController.php b/controllers/LoginController.php index 1182e2cc..304b12bc 100644 --- a/controllers/LoginController.php +++ b/controllers/LoginController.php @@ -6,11 +6,6 @@ use Grocy\Services\SessionService; class LoginController extends BaseController { - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } - public function LoginPage(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { return $this->renderPage($response, 'login'); diff --git a/controllers/OpenApiController.php b/controllers/OpenApiController.php index 14aa8194..f1517908 100644 --- a/controllers/OpenApiController.php +++ b/controllers/OpenApiController.php @@ -85,9 +85,4 @@ class OpenApiController extends BaseApiController { return $this->render($response, 'openapiui'); } - - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } } diff --git a/controllers/PrintApiController.php b/controllers/PrintApiController.php index d419be8d..511078ff 100644 --- a/controllers/PrintApiController.php +++ b/controllers/PrintApiController.php @@ -34,9 +34,4 @@ class PrintApiController extends BaseApiController return $this->GenericErrorResponse($response, $ex->getMessage()); } } - - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } } diff --git a/controllers/RecipesApiController.php b/controllers/RecipesApiController.php index 46091c84..263d3998 100644 --- a/controllers/RecipesApiController.php +++ b/controllers/RecipesApiController.php @@ -76,9 +76,4 @@ class RecipesApiController extends BaseApiController return $this->GenericErrorResponse($response, $ex->getMessage()); } } - - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } } diff --git a/controllers/RecipesController.php b/controllers/RecipesController.php index af8e99ae..bfc6507e 100644 --- a/controllers/RecipesController.php +++ b/controllers/RecipesController.php @@ -8,19 +8,21 @@ class RecipesController extends BaseController { public function MealPlan(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - // Given date is always the first day of the week => load the coming week / 7 days - if (isset($request->getQueryParams()['week']) && IsIsoDate($request->getQueryParams()['week'])) + $start = date('Y-m-d'); + if (isset($request->getQueryParams()['start']) && IsIsoDate($request->getQueryParams()['start'])) { - $week = $request->getQueryParams()['week']; - $mealPlanWhereTimespan = "day BETWEEN DATE('$week') AND DATE('$week', '+7 days')"; + $start = $request->getQueryParams()['start']; } - else + + $days = 6; + if (isset($request->getQueryParams()['days']) && filter_var($request->getQueryParams()['days'], FILTER_VALIDATE_INT) !== false) { - $mealPlanWhereTimespan = "day BETWEEN DATE('now', 'localtime', 'weekday 0', '-7 days') AND DATE(DATE('now', 'localtime', 'weekday 0', '-7 days'), '+7 days')"; + $days = $request->getQueryParams()['days']; } + $mealPlanWhereTimespan = "day BETWEEN DATE('$start') AND DATE('$start', '+$days days')"; + $recipes = $this->getDatabase()->recipes()->where('type', RecipesService::RECIPE_TYPE_NORMAL)->fetchAll(); - $events = []; foreach ($this->getDatabase()->meal_plan()->where($mealPlanWhereTimespan) as $mealPlanEntry) { @@ -214,9 +216,4 @@ class RecipesController extends BaseController 'mealplanSections' => $this->getDatabase()->meal_plan_sections()->where('id > 0')->orderBy('sort_number') ]); } - - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } } diff --git a/controllers/StockApiController.php b/controllers/StockApiController.php index 0f61bf49..5ca88254 100644 --- a/controllers/StockApiController.php +++ b/controllers/StockApiController.php @@ -862,9 +862,4 @@ class StockApiController extends BaseApiController return $this->GenericErrorResponse($response, $ex->getMessage()); } } - - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } } diff --git a/controllers/StockController.php b/controllers/StockController.php index f5bc45f6..7de604fe 100644 --- a/controllers/StockController.php +++ b/controllers/StockController.php @@ -4,11 +4,11 @@ namespace Grocy\Controllers; use Grocy\Helpers\Grocycode; use Grocy\Services\RecipesService; -use jucksearm\barcode\lib\BarcodeFactory; -use jucksearm\barcode\lib\DatamatrixFactory; class StockController extends BaseController { + use GrocycodeTrait; + public function Consume(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { return $this->renderPage($response, 'consume', [ @@ -192,36 +192,8 @@ class StockController extends BaseController public function ProductGrocycodeImage(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - $size = $request->getQueryParam('size', null); $gc = new Grocycode(Grocycode::PRODUCT, $args['productId']); - - if (GROCY_GROCYCODE_TYPE == '2D') - { - $png = (new DatamatrixFactory())->setCode((string) $gc)->setSize($size)->getDatamatrixPngData(); - } - else - { - $png = (new BarcodeFactory())->setType('C128')->setCode((string) $gc)->setHeight($size)->getBarcodePngData(); - } - - $isDownload = $request->getQueryParam('download', false); - if ($isDownload) - { - $response = $response->withHeader('Content-Type', 'application/octet-stream') - ->withHeader('Content-Disposition', 'attachment; filename=grocycode.png') - ->withHeader('Content-Length', strlen($png)) - ->withHeader('Cache-Control', 'no-cache') - ->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT'); - } - else - { - $response = $response->withHeader('Content-Type', 'image/png') - ->withHeader('Content-Length', strlen($png)) - ->withHeader('Cache-Control', 'no-cache') - ->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT'); - } - $response->getBody()->write($png); - return $response; + return $this->ServeGrocycodeImage($request, $response, $gc); } public function ProductGroupEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) @@ -488,38 +460,9 @@ class StockController extends BaseController public function StockEntryGrocycodeImage(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { - $size = $request->getQueryParam('size', null); - $stockEntry = $this->getDatabase()->stock()->where('id', $args['entryId'])->fetch(); $gc = new Grocycode(Grocycode::PRODUCT, $stockEntry->product_id, [$stockEntry->stock_id]); - - if (GROCY_GROCYCODE_TYPE == '2D') - { - $png = (new DatamatrixFactory())->setCode((string) $gc)->setSize($size)->getDatamatrixPngData(); - } - else - { - $png = (new BarcodeFactory())->setType('C128')->setCode((string) $gc)->setHeight($size)->getBarcodePngData(); - } - - $isDownload = $request->getQueryParam('download', false); - if ($isDownload) - { - $response = $response->withHeader('Content-Type', 'application/octet-stream') - ->withHeader('Content-Disposition', 'attachment; filename=grocycode.png') - ->withHeader('Content-Length', strlen($png)) - ->withHeader('Cache-Control', 'no-cache') - ->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT'); - } - else - { - $response = $response->withHeader('Content-Type', 'image/png') - ->withHeader('Content-Length', strlen($png)) - ->withHeader('Cache-Control', 'no-cache') - ->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT'); - } - $response->getBody()->write($png); - return $response; + return $this->ServeGrocycodeImage($request, $response, $gc); } public function StockEntryGrocycodeLabel(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) @@ -569,11 +512,6 @@ class StockController extends BaseController ]); } - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } - public function JournalSummary(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { $entries = $this->getDatabase()->uihelper_stock_journal_summary(); diff --git a/controllers/SystemApiController.php b/controllers/SystemApiController.php index 51019c95..913edb95 100644 --- a/controllers/SystemApiController.php +++ b/controllers/SystemApiController.php @@ -89,9 +89,4 @@ class SystemApiController extends BaseApiController { return $this->ApiResponse($response, json_decode($this->getLocalizationService()->GetPoAsJsonString()), true); } - - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } } diff --git a/controllers/SystemController.php b/controllers/SystemController.php index b358c90d..119964cf 100644 --- a/controllers/SystemController.php +++ b/controllers/SystemController.php @@ -35,11 +35,6 @@ class SystemController extends BaseController return $response->withRedirect($this->AppContainer->get('UrlManager')->ConstructUrl($this->GetEntryPageRelative())); } - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } - /** * Get the entry page of the application based on the value of the entry page setting. * diff --git a/controllers/TasksApiController.php b/controllers/TasksApiController.php index eba0f4ee..5ccffc0d 100644 --- a/controllers/TasksApiController.php +++ b/controllers/TasksApiController.php @@ -49,9 +49,4 @@ class TasksApiController extends BaseApiController return $this->GenericErrorResponse($response, $ex->getMessage()); } } - - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } } diff --git a/controllers/TasksController.php b/controllers/TasksController.php index 7adca972..08eeee4d 100644 --- a/controllers/TasksController.php +++ b/controllers/TasksController.php @@ -83,9 +83,4 @@ class TasksController extends BaseController { return $this->renderPage($response, 'taskssettings'); } - - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } } diff --git a/controllers/Users/User.php b/controllers/Users/User.php index 4979c144..b260be67 100644 --- a/controllers/Users/User.php +++ b/controllers/Users/User.php @@ -67,6 +67,11 @@ class User const PERMISSION_USERS_READ = 'USERS_READ'; + public function __construct() + { + $this->db = DatabaseService::getInstance()->GetDbConnection(); + } + /** * @var \LessQL\Database|null */ @@ -78,11 +83,6 @@ class User return $user->getPermissionList(); } - public function __construct() - { - $this->db = DatabaseService::getInstance()->GetDbConnection(); - } - public static function checkPermission($request, string ...$permissions): void { $user = new self(); diff --git a/controllers/UsersApiController.php b/controllers/UsersApiController.php index b14a84f4..bc724603 100644 --- a/controllers/UsersApiController.php +++ b/controllers/UsersApiController.php @@ -231,9 +231,4 @@ class UsersApiController extends BaseApiController return $this->GenericErrorResponse($response, $ex->getMessage()); } } - - public function __construct(\DI\Container $container) - { - parent::__construct($container); - } } diff --git a/helpers/BaseBarcodeLookupPlugin.php b/helpers/BaseBarcodeLookupPlugin.php index 6e97dc00..c4df8f33 100644 --- a/helpers/BaseBarcodeLookupPlugin.php +++ b/helpers/BaseBarcodeLookupPlugin.php @@ -4,6 +4,12 @@ namespace Grocy\Helpers; abstract class BaseBarcodeLookupPlugin { + final public function __construct($locations, $quantityUnits) + { + $this->Locations = $locations; + $this->QuantityUnits = $quantityUnits; + } + protected $Locations; protected $QuantityUnits; @@ -50,28 +56,24 @@ abstract class BaseBarcodeLookupPlugin // Check referenced entity ids are valid $locationId = $pluginOutput['location_id']; - if (FindObjectInArrayByPropertyValue($this->Locations, 'id', $locationId) === null) { throw new \Exception("Location $locationId is not a valid location id"); } $quIdPurchase = $pluginOutput['qu_id_purchase']; - if (FindObjectInArrayByPropertyValue($this->QuantityUnits, 'id', $quIdPurchase) === null) { throw new \Exception("Location $quIdPurchase is not a valid quantity unit id"); } $quIdStock = $pluginOutput['qu_id_stock']; - if (FindObjectInArrayByPropertyValue($this->QuantityUnits, 'id', $quIdStock) === null) { throw new \Exception("Location $quIdStock is not a valid quantity unit id"); } $quFactor = $pluginOutput['qu_factor_purchase_to_stock']; - if (empty($quFactor) || !is_numeric($quFactor)) { throw new \Exception('Quantity unit factor is empty or not a number'); @@ -80,11 +82,5 @@ abstract class BaseBarcodeLookupPlugin return $pluginOutput; } - final public function __construct($locations, $quantityUnits) - { - $this->Locations = $locations; - $this->QuantityUnits = $quantityUnits; - } - abstract protected function ExecuteLookup($barcode); } diff --git a/helpers/Grocycode.php b/helpers/Grocycode.php index 5f8a9907..3f9af599 100644 --- a/helpers/Grocycode.php +++ b/helpers/Grocycode.php @@ -25,6 +25,33 @@ class Grocycode public const MAGIC = 'grcy'; + /** + * Constructs a new instance of the Grocycode class. + * + * Because php doesn't support overloading, this is a proxy + * to either setFromCode($code) or setFromData($type, $id, $extra_data = []). + */ + public function __construct(...$args) + { + $argc = count($args); + if ($argc == 1) + { + $this->setFromCode($args[0]); + return; + } + elseif ($argc == 2 || $argc == 3) + { + if ($argc == 2) + { + $args[] = []; + } + $this->setFromData($args[0], $args[1], $args[2]); + return; + } + + throw new \Exception('No suitable overload found.'); + } + /** * An array that registers all valid grocycode types. Register yours here by appending to this array. */ @@ -56,31 +83,26 @@ class Grocycode } } - /** - * Constructs a new instance of the Grocycode class. - * - * Because php doesn't support overloading, this is a proxy - * to either setFromCode($code) or setFromData($type, $id, $extra_data = []). - */ - public function __construct(...$args) + public function GetId() { - $argc = count($args); - if ($argc == 1) - { - $this->setFromCode($args[0]); - return; - } - elseif ($argc == 2 || $argc == 3) - { - if ($argc == 2) - { - $args[] = []; - } - $this->setFromData($args[0], $args[1], $args[2]); - return; - } + return $this->id; + } - throw new \Exception('No suitable overload found.'); + public function GetExtraData() + { + return $this->extra_data; + } + + public function GetType() + { + return $this->type; + } + + public function __toString(): string + { + $arr = array_merge([self::MAGIC, $this->type, $this->id], $this->extra_data); + + return implode(':', $arr); } /** @@ -121,26 +143,4 @@ class Grocycode $this->id = $id; $this->extra_data = $extra_data; } - - public function GetId() - { - return $this->id; - } - - public function GetExtraData() - { - return $this->extra_data; - } - - public function GetType() - { - return $this->type; - } - - public function __toString(): string - { - $arr = array_merge([self::MAGIC, $this->type, $this->id], $this->extra_data); - - return implode(':', $arr); - } } diff --git a/helpers/UrlManager.php b/helpers/UrlManager.php index 4f137a36..af83476d 100644 --- a/helpers/UrlManager.php +++ b/helpers/UrlManager.php @@ -4,6 +4,18 @@ namespace Grocy\Helpers; class UrlManager { + public function __construct(string $basePath) + { + if ($basePath === '/') + { + $this->BasePath = $this->GetBaseUrl(); + } + else + { + $this->BasePath = $basePath; + } + } + protected $BasePath; public function ConstructUrl($relativePath, $isResource = false) @@ -18,18 +30,6 @@ class UrlManager } } - public function __construct(string $basePath) - { - if ($basePath === '/') - { - $this->BasePath = $this->GetBaseUrl(); - } - else - { - $this->BasePath = $basePath; - } - } - private function GetBaseUrl() { if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false) diff --git a/helpers/WebhookRunner.php b/helpers/WebhookRunner.php index a7a1aa25..150155a5 100644 --- a/helpers/WebhookRunner.php +++ b/helpers/WebhookRunner.php @@ -8,13 +8,13 @@ use Psr\Http\Message\ResponseInterface; class WebhookRunner { - private $client; - public function __construct() { $this->client = new Client(['timeout' => 2.0]); } + private $client; + public function run($url, $args, $json = false) { $reqArgs = []; diff --git a/helpers/extensions.php b/helpers/extensions.php index c17f6ab7..27c25f60 100644 --- a/helpers/extensions.php +++ b/helpers/extensions.php @@ -4,8 +4,7 @@ function FindObjectInArrayByPropertyValue($array, $propertyName, $propertyValue) { foreach ($array as $object) { - if ($object->{$propertyName} - == $propertyValue) + if ($object->{$propertyName} == $propertyValue) { return $object; } @@ -17,37 +16,28 @@ function FindObjectInArrayByPropertyValue($array, $propertyName, $propertyValue) function FindAllObjectsInArrayByPropertyValue($array, $propertyName, $propertyValue, $operator = '==') { $returnArray = []; - foreach ($array as $object) { switch ($operator) { case '==': - - if ($object->{$propertyName} - == $propertyValue) + if ($object->{$propertyName} == $propertyValue) { $returnArray[] = $object; } - break; case '>': - - if ($object->{$propertyName} - > $propertyValue) + if ($object->{$propertyName} > $propertyValue) { $returnArray[] = $object; } - break; case '<': - if ($object->{$propertyName} - < $propertyValue) + if ($object->{$propertyName} < $propertyValue) { $returnArray[] = $object; } - break; } } @@ -58,7 +48,6 @@ function FindAllObjectsInArrayByPropertyValue($array, $propertyName, $propertyVa function FindAllItemsInArrayByValue($array, $value, $operator = '==') { $returnArray = []; - foreach ($array as $item) { switch ($operator) @@ -69,7 +58,6 @@ function FindAllItemsInArrayByValue($array, $value, $operator = '==') { $returnArray[] = $item; } - break; case '>': @@ -77,7 +65,6 @@ function FindAllItemsInArrayByValue($array, $value, $operator = '==') { $returnArray[] = $item; } - break; case '<': @@ -85,7 +72,6 @@ function FindAllItemsInArrayByValue($array, $value, $operator = '==') { $returnArray[] = $item; } - break; } } @@ -96,7 +82,6 @@ function FindAllItemsInArrayByValue($array, $value, $operator = '==') function SumArrayValue($array, $propertyName) { $sum = 0; - foreach ($array as $object) { $sum += floatval($object->{$propertyName}); @@ -124,7 +109,6 @@ function GetClassConstants($className, $prefix = null) function RandomString($length, $allowedChars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') { $randomString = ''; - for ($i = 0; $i < $length; $i++) { $randomString .= $allowedChars[rand(0, strlen($allowedChars) - 1)]; @@ -190,7 +174,8 @@ function Setting(string $name, $value) define('GROCY_' . $name, ExternalSettingValue(file_get_contents($settingOverrideFile))); } elseif (getenv('GROCY_' . $name) !== false) - { // An environment variable with the same name and prefix GROCY_ overwrites the given setting + { + // An environment variable with the same name and prefix GROCY_ overwrites the given setting define('GROCY_' . $name, ExternalSettingValue(getenv('GROCY_' . $name))); } else diff --git a/localization/he_IL/demo_data.po b/localization/he_IL/demo_data.po index 2d038990..64327717 100644 --- a/localization/he_IL/demo_data.po +++ b/localization/he_IL/demo_data.po @@ -2,7 +2,7 @@ # Translators: # Adi Zarko , 2020 # Netanel Lazarovich , 2020 -# Yaron Shahrabani , 2020 +# Yaron Shahrabani , 2021 # msgid "" msgstr "" @@ -10,7 +10,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2019-05-01T17:59:17+00:00\n" "PO-Revision-Date: 2019-05-01 17:42+0000\n" -"Last-Translator: Yaron Shahrabani , 2020\n" +"Last-Translator: Yaron Shahrabani , 2021\n" "Language-Team: Hebrew (Israel) (https://www.transifex.com/grocy/teams/93189/he_IL/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -402,10 +402,10 @@ msgid "Finnish" msgstr "פינית" msgid "Breakfast" -msgstr "" +msgstr "ארוחת בוקר" msgid "Lunch" -msgstr "" +msgstr "ארוחת צהריים" msgid "Dinner" -msgstr "" +msgstr "ארוחת ערב" diff --git a/localization/he_IL/strings.po b/localization/he_IL/strings.po index c9f0560a..bf23baa3 100644 --- a/localization/he_IL/strings.po +++ b/localization/he_IL/strings.po @@ -2481,22 +2481,22 @@ msgid "Stock entry" msgstr "רשומה במלאי" msgid "Configure sections" -msgstr "" +msgstr "הגדרת סעיפים" msgid "Meal plan sections" -msgstr "" +msgstr "סעיפי תכנית ארוחות" msgid "Create meal plan section" -msgstr "" +msgstr "יצירת סעיף תכנית ארוחות" msgid "Sections will be ordered by that number on the meal plan" -msgstr "" +msgstr "הסעיפים יסודרו לפי המספר על תכנית הארוחות" msgid "Edit meal plan section" -msgstr "" +msgstr "עריכת סעיף תכנית ארוחות" msgid "Are you sure to delete meal plan section \"%s\"?" -msgstr "" +msgstr "למחוק את הסעיף „%s” מתכנית הארוחות?" msgid "Section" -msgstr "" +msgstr "סעיף" diff --git a/middleware/ApiKeyAuthMiddleware.php b/middleware/ApiKeyAuthMiddleware.php index ea65025d..7cce2bcd 100644 --- a/middleware/ApiKeyAuthMiddleware.php +++ b/middleware/ApiKeyAuthMiddleware.php @@ -9,14 +9,14 @@ use Slim\Routing\RouteContext; class ApiKeyAuthMiddleware extends AuthMiddleware { - protected $ApiKeyHeaderName; - public function __construct(\DI\Container $container, ResponseFactoryInterface $responseFactory) { parent::__construct($container, $responseFactory); $this->ApiKeyHeaderName = $this->AppContainer->get('ApiKeyHeaderName'); } + protected $ApiKeyHeaderName; + public function authenticate(Request $request) { $routeContext = RouteContext::fromRequest($request); diff --git a/middleware/AuthMiddleware.php b/middleware/AuthMiddleware.php index 3b3d75f0..bb4fe443 100644 --- a/middleware/AuthMiddleware.php +++ b/middleware/AuthMiddleware.php @@ -11,14 +11,14 @@ use Slim\Routing\RouteContext; abstract class AuthMiddleware extends BaseMiddleware { - protected $ResponseFactory; - public function __construct(\DI\Container $container, ResponseFactoryInterface $responseFactory) { parent::__construct($container); $this->ResponseFactory = $responseFactory; } + protected $ResponseFactory; + public function __invoke(Request $request, RequestHandler $handler): Response { $routeContext = RouteContext::fromRequest($request); diff --git a/middleware/LocaleMiddleware.php b/middleware/LocaleMiddleware.php index c0acede4..3b2f6b06 100644 --- a/middleware/LocaleMiddleware.php +++ b/middleware/LocaleMiddleware.php @@ -21,7 +21,6 @@ class LocaleMiddleware extends BaseMiddleware if (defined('GROCY_AUTHENTICATED') && GROCY_AUTHENTICATED) { $locale = UsersService::getInstance()->GetUserSetting(GROCY_USER_ID, 'locale'); - if (isset($locale) && !empty($locale)) { if (in_array($locale, scandir(__DIR__ . '/../localization'))) @@ -46,7 +45,6 @@ class LocaleMiddleware extends BaseMiddleware arsort($prefLocales); $availableLocales = scandir(__DIR__ . '/../localization'); - foreach ($prefLocales as $locale => $q) { if (in_array($locale, $availableLocales)) @@ -60,7 +58,7 @@ class LocaleMiddleware extends BaseMiddleware return substr($locale, 0, 5); } - // e.g: cs + // e.g. cs if (in_array(substr($locale, 0, 2), $availableLocales)) { return substr($locale, 0, 2); diff --git a/migrations/0149.sql b/migrations/0149.sql index cade364f..6e135eeb 100644 --- a/migrations/0149.sql +++ b/migrations/0149.sql @@ -12,3 +12,13 @@ VALUES ALTER TABLE meal_plan ADD section_id INTEGER NOT NULL DEFAULT -1; + +CREATE TRIGGER prevent_internal_meal_plan_section_removal BEFORE DELETE ON meal_plan_sections +BEGIN + SELECT CASE WHEN(( + SELECT 1 + FROM meal_plan_sections + WHERE id = OLD.id + AND id = -1 + ) NOTNULL) THEN RAISE(ABORT, "This is an internally used/required default section and therefore can't be deleted") END; +END; diff --git a/public/js/grocy.js b/public/js/grocy.js index 73f0dc6b..1208f6ef 100644 --- a/public/js/grocy.js +++ b/public/js/grocy.js @@ -1116,5 +1116,12 @@ $(document).on("click", ".change-table-columns-rowgroup-toggle", function() if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_RECIPES) { - $("#meal-plan-nav-link").attr("href", $("#meal-plan-nav-link").attr("href") + "?week=" + moment().startOf("week").format("YYYY-MM-DD")); + if ($(window).width() < 768) + { + $("#meal-plan-nav-link").attr("href", $("#meal-plan-nav-link").attr("href") + "?start=" + moment().format("YYYY-MM-DD") + "&days=0"); + } + else + { + $("#meal-plan-nav-link").attr("href", $("#meal-plan-nav-link").attr("href") + "?start=" + moment().startOf("week").format("YYYY-MM-DD")); + } } diff --git a/public/viewjs/mealplan.js b/public/viewjs/mealplan.js index 4775f915..ed8369b5 100644 --- a/public/viewjs/mealplan.js +++ b/public/viewjs/mealplan.js @@ -48,7 +48,7 @@ $(".calendar").each(function() "scrollTime": "00:00:00", "firstDay": firstDay, "height": "auto", - "defaultDate": GetUriParam("week"), + "defaultDate": GetUriParam("start"), "viewRender": function(view) { if (!isPrimarySection) @@ -309,7 +309,7 @@ $(".calendar").each(function() { if (isPrimarySection) { - UpdateUriParam("week", view.start.format("YYYY-MM-DD")); + UpdateUriParam("start", view.start.format("YYYY-MM-DD")); if (firstRender) { diff --git a/services/ApplicationService.php b/services/ApplicationService.php index 819572ff..ef244d13 100644 --- a/services/ApplicationService.php +++ b/services/ApplicationService.php @@ -9,7 +9,6 @@ class ApplicationService extends BaseService public function GetChangelog() { $changelogItems = []; - foreach (glob(__DIR__ . '/../changelog/*.md') as $file) { $fileName = basename($file); diff --git a/services/BaseService.php b/services/BaseService.php index 0dc60297..cff227d8 100644 --- a/services/BaseService.php +++ b/services/BaseService.php @@ -6,14 +6,9 @@ class BaseService { private static $instances = []; - public function __construct() - { - } - public static function getInstance() { $className = get_called_class(); - if (!isset(self::$instances[$className])) { self::$instances[$className] = new $className(); diff --git a/services/CalendarService.php b/services/CalendarService.php index 91ded607..373a3649 100644 --- a/services/CalendarService.php +++ b/services/CalendarService.php @@ -6,6 +6,13 @@ use Grocy\Helpers\UrlManager; class CalendarService extends BaseService { + public function __construct() + { + $this->UrlManager = new UrlManager(GROCY_BASE_URL); + } + + private $UrlManager; + public function GetEvents() { $stockEvents = []; @@ -148,10 +155,4 @@ class CalendarService extends BaseService return array_merge($stockEvents, $taskEvents, $choreEvents, $batteryEvents, $mealPlanRecipeEvents, $mealPlanNotesEvents, $mealPlanProductEvents); } - - public function __construct() - { - parent::__construct(); - $this->UrlManager = new UrlManager(GROCY_BASE_URL); - } } diff --git a/services/ChoresService.php b/services/ChoresService.php index 7f7da859..7f265bfb 100644 --- a/services/ChoresService.php +++ b/services/ChoresService.php @@ -38,7 +38,6 @@ class ChoresService extends BaseService $users = $this->getUsersService()->GetUsersAsDto(); $assignedUsers = []; - foreach ($users as $user) { if (in_array($user->id, explode(',', $chore->assignment_config))) @@ -210,11 +209,6 @@ class ChoresService extends BaseService ]); } - public function __construct() - { - parent::__construct(); - } - private function ChoreExists($choreId) { $choreRow = $this->getDatabase()->chores()->where('id = :1', $choreId)->fetch(); diff --git a/services/DatabaseMigrationService.php b/services/DatabaseMigrationService.php index 8385d8e8..014096aa 100644 --- a/services/DatabaseMigrationService.php +++ b/services/DatabaseMigrationService.php @@ -4,6 +4,9 @@ namespace Grocy\Services; class DatabaseMigrationService extends BaseService { + // This migration will be always execute, can be used to fix things manually + const EMERGENCY_MIGRATION_ID = 9999; + public function MigrateDatabase() { $this->getDatabaseService()->ExecuteDbStatement("CREATE TABLE IF NOT EXISTS migrations (migration INTEGER NOT NULL PRIMARY KEY UNIQUE, execution_time_timestamp DATETIME DEFAULT (datetime('now', 'localtime')))"); @@ -36,10 +39,14 @@ class DatabaseMigrationService extends BaseService { $rowCount = $this->getDatabaseService()->ExecuteDbQuery('SELECT COUNT(*) FROM migrations WHERE migration = ' . $migrationId)->fetchColumn(); - if (intval($rowCount) === 0) + if (intval($rowCount) === 0 || $migrationId == self::EMERGENCY_MIGRATION_ID) { include $phpFile; - $this->getDatabaseService()->ExecuteDbStatement('INSERT INTO migrations (migration) VALUES (' . $migrationId . ')'); + + if ($migrationId != self::EMERGENCY_MIGRATION_ID) + { + $this->getDatabaseService()->ExecuteDbStatement('INSERT INTO migrations (migration) VALUES (' . $migrationId . ')'); + } } } @@ -47,14 +54,18 @@ class DatabaseMigrationService extends BaseService { $rowCount = $this->getDatabaseService()->ExecuteDbQuery('SELECT COUNT(*) FROM migrations WHERE migration = ' . $migrationId)->fetchColumn(); - if (intval($rowCount) === 0) + if (intval($rowCount) === 0 || $migrationId == self::EMERGENCY_MIGRATION_ID) { $this->getDatabaseService()->GetDbConnectionRaw()->beginTransaction(); try { $this->getDatabaseService()->ExecuteDbStatement($sql); - $this->getDatabaseService()->ExecuteDbStatement('INSERT INTO migrations (migration) VALUES (' . $migrationId . ')'); + + if ($migrationId != self::EMERGENCY_MIGRATION_ID) + { + $this->getDatabaseService()->ExecuteDbStatement('INSERT INTO migrations (migration) VALUES (' . $migrationId . ')'); + } } catch (Exception $ex) { diff --git a/services/DemoDataGeneratorService.php b/services/DemoDataGeneratorService.php index d57552fc..80c26966 100644 --- a/services/DemoDataGeneratorService.php +++ b/services/DemoDataGeneratorService.php @@ -4,6 +4,11 @@ namespace Grocy\Services; class DemoDataGeneratorService extends BaseService { + public function __construct() + { + $this->LocalizationService = new LocalizationService(GROCY_DEFAULT_LOCALE); + } + protected $LocalizationService; private $LastSupermarketId = 1; @@ -343,12 +348,6 @@ class DemoDataGeneratorService extends BaseService } } - public function __construct() - { - parent::__construct(); - $this->LocalizationService = new LocalizationService(GROCY_DEFAULT_LOCALE); - } - private function DownloadFileIfNotAlreadyExists($sourceUrl, $destinationPath) { if (!file_exists($destinationPath)) diff --git a/services/FilesService.php b/services/FilesService.php index 053dd034..7d070350 100644 --- a/services/FilesService.php +++ b/services/FilesService.php @@ -8,6 +8,30 @@ class FilesService extends BaseService { const FILE_SERVE_TYPE_PICTURE = 'picture'; + public function __construct() + { + $this->StoragePath = GROCY_DATAPATH . '/storage'; + if (!file_exists($this->StoragePath)) + { + mkdir($this->StoragePath); + } + + if (GROCY_MODE === 'demo' || GROCY_MODE === 'prerelease') + { + $dbSuffix = GROCY_DEFAULT_LOCALE; + if (defined('GROCY_DEMO_DB_SUFFIX')) + { + $dbSuffix = GROCY_DEMO_DB_SUFFIX; + } + + $this->StoragePath = $this->StoragePath . '/' . $dbSuffix; + if (!file_exists($this->StoragePath)) + { + mkdir($this->StoragePath); + } + } + } + private $StoragePath; public function DownscaleImage($group, $fileName, $bestFitHeight = null, $bestFitWidth = null) @@ -58,8 +82,9 @@ class FilesService extends BaseService $fileNameWithoutExtension = pathinfo($filePath, PATHINFO_FILENAME); $fileExtension = pathinfo($filePath, PATHINFO_EXTENSION); + // Then the file is an image if (getimagesize($filePath) !== false) - { // Then the file is an image + { // Also delete all corresponding "__downscaledto" files when deleting an image $groupFolderPath = $this->StoragePath . '/' . $group; $files = scandir($groupFolderPath); @@ -87,32 +112,4 @@ class FilesService extends BaseService return $groupFolderPath . '/' . $fileName; } - - public function __construct() - { - parent::__construct(); - - $this->StoragePath = GROCY_DATAPATH . '/storage'; - - if (!file_exists($this->StoragePath)) - { - mkdir($this->StoragePath); - } - - if (GROCY_MODE === 'demo' || GROCY_MODE === 'prerelease') - { - $dbSuffix = GROCY_DEFAULT_LOCALE; - if (defined('GROCY_DEMO_DB_SUFFIX')) - { - $dbSuffix = GROCY_DEMO_DB_SUFFIX; - } - - $this->StoragePath = $this->StoragePath . '/' . $dbSuffix; - - if (!file_exists($this->StoragePath)) - { - mkdir($this->StoragePath); - } - } - } } diff --git a/services/LocalizationService.php b/services/LocalizationService.php index 7a19d633..58013998 100644 --- a/services/LocalizationService.php +++ b/services/LocalizationService.php @@ -8,6 +8,13 @@ use Gettext\Translator; class LocalizationService { + public function __construct(string $culture) + { + $this->Culture = $culture; + + $this->LoadLocalizations($culture); + } + protected $Po; protected $PoUserStrings; @@ -62,13 +69,6 @@ class LocalizationService return $this->Po->toJsonString(); } - public function __construct(string $culture) - { - $this->Culture = $culture; - - $this->LoadLocalizations($culture); - } - public function __n($number, $singularForm, $pluralForm) { $this->CheckAndAddMissingTranslationToPot($singularForm); diff --git a/services/PrintService.php b/services/PrintService.php index c6f1053b..220bbb55 100644 --- a/services/PrintService.php +++ b/services/PrintService.php @@ -10,6 +10,39 @@ use Mike42\Escpos\Printer; class PrintService extends BaseService { + /** + * @param bool $printHeader Printing of Grocy logo + * @param string[] $lines Items to print + * @return string[] Returns array with result OK if no exception + * @throws Exception If unable to print, an exception is thrown + */ + public function printShoppingList(bool $printHeader, array $lines): array + { + $printer = self::getPrinterHandle(); + if ($printer === false) + { + throw new Exception('Unable to connect to printer'); + } + + if ($printHeader) + { + self::printHeader($printer); + } + + foreach ($lines as $line) + { + $printer->text($line); + $printer->feed(); + } + + $printer->feed(3); + $printer->cut(); + $printer->close(); + return [ + 'result' => 'OK' + ]; + } + /** * Initialises the printer * @return Printer Printer handle @@ -50,37 +83,4 @@ class PrintService extends BaseService $printer->selectPrintMode(); $printer->feed(2); } - - /** - * @param bool $printHeader Printing of Grocy logo - * @param string[] $lines Items to print - * @return string[] Returns array with result OK if no exception - * @throws Exception If unable to print, an exception is thrown - */ - public function printShoppingList(bool $printHeader, array $lines): array - { - $printer = self::getPrinterHandle(); - if ($printer === false) - { - throw new Exception('Unable to connect to printer'); - } - - if ($printHeader) - { - self::printHeader($printer); - } - - foreach ($lines as $line) - { - $printer->text($line); - $printer->feed(); - } - - $printer->feed(3); - $printer->cut(); - $printer->close(); - return [ - 'result' => 'OK' - ]; - } } diff --git a/services/RecipesService.php b/services/RecipesService.php index 0cdc126b..b98b689c 100644 --- a/services/RecipesService.php +++ b/services/RecipesService.php @@ -63,8 +63,8 @@ class RecipesService extends BaseService } $transactionId = uniqid(); - $recipePositions = $this->getDatabase()->recipes_pos_resolved()->where('recipe_id', $recipeId)->fetchAll(); + $recipePositions = $this->getDatabase()->recipes_pos_resolved()->where('recipe_id', $recipeId)->fetchAll(); foreach ($recipePositions as $recipePosition) { if ($recipePosition->only_check_single_unit_in_stock == 0) @@ -129,11 +129,6 @@ class RecipesService extends BaseService return $lastInsertId; } - public function __construct() - { - parent::__construct(); - } - private function RecipeExists($recipeId) { $recipeRow = $this->getDataBase()->recipes()->where('id = :1', $recipeId)->fetch(); diff --git a/services/SessionService.php b/services/SessionService.php index d7033b7c..89013bbc 100644 --- a/services/SessionService.php +++ b/services/SessionService.php @@ -12,7 +12,6 @@ class SessionService extends BaseService public function CreateSession($userId, $stayLoggedInPermanently = false) { $newSessionKey = $this->GenerateSessionKey(); - $expires = date('Y-m-d H:i:s', intval(time() + 2592000)); // Default is that sessions expire in 30 days @@ -39,7 +38,6 @@ class SessionService extends BaseService public function GetUserBySessionKey($sessionKey) { $sessionRow = $this->getDatabase()->sessions()->where('session_key', $sessionKey)->fetch(); - if ($sessionRow !== null) { return $this->getDatabase()->users($sessionRow->user_id); @@ -60,7 +58,6 @@ class SessionService extends BaseService else { $sessionRow = $this->getDatabase()->sessions()->where('session_key = :1 AND expires > :2', $sessionKey, date('Y-m-d H:i:s', time()))->fetch(); - if ($sessionRow !== null) { // This should not change the database file modification time as this is used diff --git a/services/StockService.php b/services/StockService.php index bf4695a6..f73ac5bd 100644 --- a/services/StockService.php +++ b/services/StockService.php @@ -33,7 +33,6 @@ class StockService extends BaseService } $missingProducts = $this->GetMissingProducts(); - foreach ($missingProducts as $missingProduct) { $product = $this->getDatabase()->products()->where('id', $missingProduct->id)->fetch(); @@ -42,7 +41,8 @@ class StockService extends BaseService $alreadyExistingEntry = $this->getDatabase()->shopping_list()->where('product_id', $missingProduct->id)->fetch(); if ($alreadyExistingEntry) - { // Update + { + // Update if ($alreadyExistingEntry->amount < $amountToAdd) { $alreadyExistingEntry->update([ @@ -52,7 +52,8 @@ class StockService extends BaseService } } else - { // Insert + { + // Insert $shoppinglistRow = $this->getDatabase()->shopping_list()->createRow([ 'product_id' => $missingProduct->id, 'amount' => $amountToAdd, @@ -197,7 +198,8 @@ class StockService extends BaseService { $reps = 1; if ($runWebhook == 2) - { // 2 == run $amount times + { + // 2 == run $amount times $reps = intval(floor($amount)); } @@ -428,7 +430,6 @@ class StockService extends BaseService public function EditStockEntry(int $stockRowId, float $amount, $bestBeforeDate, $locationId, $shoppingLocationId, $price, $open, $purchasedDate) { $stockRow = $this->getDatabase()->stock()->where('id = :1', $stockRowId)->fetch(); - if ($stockRow === null) { throw new \Exception('Stock does not exist'); @@ -455,7 +456,6 @@ class StockService extends BaseService $logOldRowForStockUpdate->save(); $openedDate = $stockRow->opened_date; - if (boolval($open) && $openedDate == null) { $openedDate = date('Y-m-d'); @@ -505,7 +505,8 @@ class StockService extends BaseService $pluginOutput = $plugin->Lookup($barcode); if ($pluginOutput !== null) - { // Lookup was successful + { + // Lookup was successful if ($addFoundProduct === true) { // Add product to database and include new product id in output @@ -522,7 +523,6 @@ class StockService extends BaseService public function GetCurrentStock($includeNotInStockButMissingProducts = false) { $sql = 'SELECT * FROM stock_current'; - if ($includeNotInStockButMissingProducts) { $missingProductsView = 'stock_missing_products_including_opened'; @@ -538,7 +538,6 @@ class StockService extends BaseService $currentStockMapped = $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_GROUP | \PDO::FETCH_OBJ); $relevantProducts = $this->getDatabase()->products()->where('id IN (SELECT product_id FROM (' . $sql . ') x)'); - foreach ($relevantProducts as $product) { $currentStockMapped[$product->id][0]->product_id = $product->id; @@ -614,7 +613,6 @@ class StockService extends BaseService } $stockCurrentRow = FindObjectinArrayByPropertyValue($this->GetCurrentStock(), 'product_id', $productId); - if ($stockCurrentRow == null) { $stockCurrentRow = new \stdClass(); @@ -665,7 +663,6 @@ class StockService extends BaseService { $consumeCount = 1; } - $spoilRate = ($consumeCountSpoiled * 100.0) / $consumeCount; return [ @@ -704,7 +701,6 @@ class StockService extends BaseService } $potentialProduct = $this->getDatabase()->product_barcodes()->where('barcode = :1', $barcode)->fetch(); - if ($potentialProduct === null) { throw new \Exception("No product with barcode $barcode found"); @@ -722,8 +718,8 @@ class StockService extends BaseService $returnData = []; $shoppingLocations = $this->getDatabase()->shopping_locations(); - $rows = $this->getDatabase()->product_price_history()->where('product_id = :1', $productId)->orderBy('purchased_date', 'DESC'); + $rows = $this->getDatabase()->product_price_history()->where('product_id = :1', $productId)->orderBy('purchased_date', 'DESC'); foreach ($rows as $row) { $returnData[] = [ @@ -998,6 +994,7 @@ class StockService extends BaseService { $decimals = intval($this->getUsersService()->GetUserSetting(GROCY_USER_ID, 'stock_decimal_places_amounts')); $newAmount = $productRow->amount - $amount; + if ($newAmount < floatval('0.' . str_repeat('0', $decimals - ($decimals <= 0 ? 0 : 1)) . '1')) { $productRow->delete(); @@ -1032,13 +1029,16 @@ class StockService extends BaseService { $product = $this->getDatabase()->products()->where('id = :1', $row->product_id)->fetch(); $conversion = $this->getDatabase()->quantity_unit_conversions_resolved()->where('product_id = :1 AND from_qu_id = :2 AND to_qu_id = :3', $product->id, $product->qu_id_stock, $row->qu_id)->fetch(); + $factor = 1.0; if ($conversion != null) { $factor = floatval($conversion->factor); } + $amount = round($row->amount * $factor); $note = ''; + if (GROCY_TPRINTER_PRINT_NOTES) { if ($row->note != '') @@ -1047,6 +1047,7 @@ class StockService extends BaseService } } } + if (GROCY_TPRINTER_PRINT_QUANTITY_NAME && $isValidProduct) { $quantityname = $row->qu_name; @@ -1054,6 +1055,7 @@ class StockService extends BaseService { $quantityname = $row->qu_name_plural; } + array_push($result_quantity, $amount . ' ' . $quantityname); array_push($result_product, $row->product_name . $note); } @@ -1071,6 +1073,7 @@ class StockService extends BaseService } } } + //Add padding to look nicer $maxlength = 1; foreach ($result_quantity as $quantity) @@ -1080,6 +1083,7 @@ class StockService extends BaseService $maxlength = strlen($quantity); } } + $result = []; $length = count($result_quantity); for ($i = 0; $i < $length; $i++) @@ -1087,6 +1091,7 @@ class StockService extends BaseService $quantity = str_pad($result_quantity[$i], $maxlength); array_push($result, $quantity . ' ' . $result_product[$i]); } + return $result; } @@ -1222,7 +1227,8 @@ class StockService extends BaseService $amount -= $stockEntry->amount; } else - { // Stock entry amount is > than needed amount -> split the stock entry resp. update the amount + { + // Stock entry amount is > than needed amount -> split the stock entry resp. update the amount $restStockAmount = $stockEntry->amount - $amount; $logRowForLocationFrom = $this->getDatabase()->stock_log()->createRow([ diff --git a/services/UserfieldsService.php b/services/UserfieldsService.php index 75161e5a..0f48eddf 100644 --- a/services/UserfieldsService.php +++ b/services/UserfieldsService.php @@ -149,11 +149,6 @@ class UserfieldsService extends BaseService } } - public function __construct() - { - parent::__construct(); - } - protected function getOpenApispec() { if ($this->OpenApiSpec == null) diff --git a/services/UsersService.php b/services/UsersService.php index 6738ee9b..bc530e1d 100644 --- a/services/UsersService.php +++ b/services/UsersService.php @@ -97,7 +97,6 @@ class UsersService extends BaseService public function SetUserSetting($userId, $settingKey, $settingValue) { $settingRow = $this->getDatabase()->user_settings()->where('user_id = :1 AND key = :2', $userId, $settingKey)->fetch(); - if ($settingRow !== null) { $settingRow->update([ diff --git a/version.json b/version.json index 0e41f51e..5e5fbfce 100644 --- a/version.json +++ b/version.json @@ -1,4 +1,4 @@ { - "Version": "3.0.1", - "ReleaseDate": "2021-01-05" + "Version": "3.1.0", + "ReleaseDate": "2021-07-16" }