mirror of
https://github.com/grocy/grocy.git
synced 2025-04-29 01:32:38 +00:00
Reorganize project part 2
This commit is contained in:
parent
bcd5092427
commit
feb88ab685
@ -1,66 +0,0 @@
|
||||
<?php
|
||||
|
||||
class GrocyPhpHelper
|
||||
{
|
||||
public static function FindObjectInArrayByPropertyValue($array, $propertyName, $propertyValue)
|
||||
{
|
||||
foreach($array as $object)
|
||||
{
|
||||
if($object->{$propertyName} == $propertyValue)
|
||||
{
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function FindAllObjectsInArrayByPropertyValue($array, $propertyName, $propertyValue, $operator = '==')
|
||||
{
|
||||
$returnArray = array();
|
||||
|
||||
foreach($array as $object)
|
||||
{
|
||||
switch($operator)
|
||||
{
|
||||
case '==':
|
||||
if($object->{$propertyName} == $propertyValue)
|
||||
{
|
||||
$returnArray[] = $object;
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
if($object->{$propertyName} > $propertyValue)
|
||||
{
|
||||
$returnArray[] = $object;
|
||||
}
|
||||
break;
|
||||
case '<':
|
||||
if($object->{$propertyName} < $propertyValue)
|
||||
{
|
||||
$returnArray[] = $object;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $returnArray;
|
||||
}
|
||||
|
||||
public static function SumArrayValue($array, $propertyName)
|
||||
{
|
||||
$sum = 0;
|
||||
foreach($array as $object)
|
||||
{
|
||||
$sum += $object->{$propertyName};
|
||||
}
|
||||
|
||||
return $sum;
|
||||
}
|
||||
|
||||
public static function GetClassConstants($className)
|
||||
{
|
||||
$r = new ReflectionClass($className);
|
||||
return $r->getConstants();
|
||||
}
|
||||
}
|
@ -1,8 +1,15 @@
|
||||
{
|
||||
"require": {
|
||||
"slim/slim": "^3.8",
|
||||
"slim/php-view": "^2.2",
|
||||
"morris/lessql": "^0.3.4",
|
||||
"pavlakis/slim-cli": "^1.0"
|
||||
"pavlakis/slim-cli": "^1.0",
|
||||
"rubellum/slim-blade-view": "^0.1.1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Grocy\\Services\\": "services/",
|
||||
"Grocy\\Controllers\\": "controllers/",
|
||||
"Grocy\\Middleware\\": "middleware/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
807
composer.lock
generated
807
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "bf75d2487343249c600746a03f63cfd2",
|
||||
"content-hash": "12ebab60e283dfdab831d1cc22430d05",
|
||||
"packages": [
|
||||
{
|
||||
"name": "container-interop/container-interop",
|
||||
@ -37,6 +37,363 @@
|
||||
"homepage": "https://github.com/container-interop/container-interop",
|
||||
"time": "2017-02-14T19:40:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/inflector",
|
||||
"version": "v1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/inflector.git",
|
||||
"reference": "5527a48b7313d15261292c149e55e26eae771b0a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/inflector/zipball/5527a48b7313d15261292c149e55e26eae771b0a",
|
||||
"reference": "5527a48b7313d15261292c149e55e26eae771b0a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^6.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Roman Borschel",
|
||||
"email": "roman@code-factory.org"
|
||||
},
|
||||
{
|
||||
"name": "Benjamin Eberlei",
|
||||
"email": "kontakt@beberlei.de"
|
||||
},
|
||||
{
|
||||
"name": "Guilherme Blanco",
|
||||
"email": "guilhermeblanco@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Wage",
|
||||
"email": "jonwage@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Johannes Schmitt",
|
||||
"email": "schmittjoh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Common String Manipulations with regard to casing and singular/plural rules.",
|
||||
"homepage": "http://www.doctrine-project.org",
|
||||
"keywords": [
|
||||
"inflection",
|
||||
"pluralize",
|
||||
"singularize",
|
||||
"string"
|
||||
],
|
||||
"time": "2018-01-09T20:05:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "illuminate/container",
|
||||
"version": "v5.6.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/container.git",
|
||||
"reference": "4a42d667a05ec6d31f05b532cdac7e8e68e5ea2a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/illuminate/container/zipball/4a42d667a05ec6d31f05b532cdac7e8e68e5ea2a",
|
||||
"reference": "4a42d667a05ec6d31f05b532cdac7e8e68e5ea2a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/contracts": "5.6.*",
|
||||
"php": "^7.1.3",
|
||||
"psr/container": "~1.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.6-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Illuminate\\Container\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "The Illuminate Container package.",
|
||||
"homepage": "https://laravel.com",
|
||||
"time": "2018-01-21T02:13:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "illuminate/contracts",
|
||||
"version": "v5.6.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/contracts.git",
|
||||
"reference": "322ec80498b3bf85bc4025d028e130a9b50242b9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/illuminate/contracts/zipball/322ec80498b3bf85bc4025d028e130a9b50242b9",
|
||||
"reference": "322ec80498b3bf85bc4025d028e130a9b50242b9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3",
|
||||
"psr/container": "~1.0",
|
||||
"psr/simple-cache": "~1.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.6-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Illuminate\\Contracts\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "The Illuminate Contracts package.",
|
||||
"homepage": "https://laravel.com",
|
||||
"time": "2018-04-07T17:05:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "illuminate/events",
|
||||
"version": "v5.6.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/events.git",
|
||||
"reference": "b6e73ed40478cef2ef98d5ddb27f333291606cea"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/illuminate/events/zipball/b6e73ed40478cef2ef98d5ddb27f333291606cea",
|
||||
"reference": "b6e73ed40478cef2ef98d5ddb27f333291606cea",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/container": "5.6.*",
|
||||
"illuminate/contracts": "5.6.*",
|
||||
"illuminate/support": "5.6.*",
|
||||
"php": "^7.1.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.6-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Illuminate\\Events\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "The Illuminate Events package.",
|
||||
"homepage": "https://laravel.com",
|
||||
"time": "2018-02-26T19:00:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "illuminate/filesystem",
|
||||
"version": "v5.6.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/filesystem.git",
|
||||
"reference": "c9ab9376076cedd88a374d7281d62b619634d578"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/illuminate/filesystem/zipball/c9ab9376076cedd88a374d7281d62b619634d578",
|
||||
"reference": "c9ab9376076cedd88a374d7281d62b619634d578",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/contracts": "5.6.*",
|
||||
"illuminate/support": "5.6.*",
|
||||
"php": "^7.1.3",
|
||||
"symfony/finder": "~4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"league/flysystem": "Required to use the Flysystem local and FTP drivers (~1.0).",
|
||||
"league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).",
|
||||
"league/flysystem-cached-adapter": "Required to use the Flysystem cache (~1.0).",
|
||||
"league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).",
|
||||
"league/flysystem-sftp": "Required to use the Flysystem SFTP driver (~1.0)."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.6-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Illuminate\\Filesystem\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "The Illuminate Filesystem package.",
|
||||
"homepage": "https://laravel.com",
|
||||
"time": "2018-04-06T13:15:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "illuminate/support",
|
||||
"version": "v5.6.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/support.git",
|
||||
"reference": "fad0669f858423679497a17f973261cc32f9a5a8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/illuminate/support/zipball/fad0669f858423679497a17f973261cc32f9a5a8",
|
||||
"reference": "fad0669f858423679497a17f973261cc32f9a5a8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/inflector": "~1.1",
|
||||
"ext-mbstring": "*",
|
||||
"illuminate/contracts": "5.6.*",
|
||||
"nesbot/carbon": "^1.24.1",
|
||||
"php": "^7.1.3"
|
||||
},
|
||||
"conflict": {
|
||||
"tightenco/collect": "<5.5.33"
|
||||
},
|
||||
"suggest": {
|
||||
"illuminate/filesystem": "Required to use the composer class (5.6.*).",
|
||||
"symfony/process": "Required to use the composer class (~4.0).",
|
||||
"symfony/var-dumper": "Required to use the dd function (~4.0)."
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.6-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Illuminate\\Support\\": ""
|
||||
},
|
||||
"files": [
|
||||
"helpers.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "The Illuminate Support package.",
|
||||
"homepage": "https://laravel.com",
|
||||
"time": "2018-04-05T21:19:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "illuminate/view",
|
||||
"version": "v5.6.16",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/illuminate/view.git",
|
||||
"reference": "54eaf45ee7946d8f8cde13d5e89c5ea2e997040d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/illuminate/view/zipball/54eaf45ee7946d8f8cde13d5e89c5ea2e997040d",
|
||||
"reference": "54eaf45ee7946d8f8cde13d5e89c5ea2e997040d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/container": "5.6.*",
|
||||
"illuminate/contracts": "5.6.*",
|
||||
"illuminate/events": "5.6.*",
|
||||
"illuminate/filesystem": "5.6.*",
|
||||
"illuminate/support": "5.6.*",
|
||||
"php": "^7.1.3",
|
||||
"symfony/debug": "~4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "5.6-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Illuminate\\View\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "The Illuminate View package.",
|
||||
"homepage": "https://laravel.com",
|
||||
"time": "2018-04-03T12:56:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "morris/lessql",
|
||||
"version": "v0.3.5",
|
||||
@ -85,6 +442,59 @@
|
||||
],
|
||||
"time": "2018-01-27T13:18:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nesbot/carbon",
|
||||
"version": "1.25.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/briannesbitt/Carbon.git",
|
||||
"reference": "cbcf13da0b531767e39eb86e9687f5deba9857b4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/cbcf13da0b531767e39eb86e9687f5deba9857b4",
|
||||
"reference": "cbcf13da0b531767e39eb86e9687f5deba9857b4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.9",
|
||||
"symfony/translation": "~2.6 || ~3.0 || ~4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "~2",
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.23-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Carbon\\": "src/Carbon/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Brian Nesbitt",
|
||||
"email": "brian@nesbot.com",
|
||||
"homepage": "http://nesbot.com"
|
||||
}
|
||||
],
|
||||
"description": "A simple API extension for DateTime.",
|
||||
"homepage": "http://carbon.nesbot.com",
|
||||
"keywords": [
|
||||
"date",
|
||||
"datetime",
|
||||
"time"
|
||||
],
|
||||
"time": "2018-03-19T15:50:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/fast-route",
|
||||
"version": "v1.3.0",
|
||||
@ -180,6 +590,47 @@
|
||||
],
|
||||
"time": "2017-01-30T22:50:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "philo/laravel-blade",
|
||||
"version": "v3.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PhiloNL/Laravel-Blade.git",
|
||||
"reference": "3f0ce2ee198604c53c25188110e6d7b5e887527a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PhiloNL/Laravel-Blade/zipball/3f0ce2ee198604c53c25188110e6d7b5e887527a",
|
||||
"reference": "3f0ce2ee198604c53c25188110e6d7b5e887527a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/events": "~5",
|
||||
"illuminate/view": "~5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Philo\\Blade\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Philo Hermans",
|
||||
"email": "me@philohermans.com"
|
||||
}
|
||||
],
|
||||
"description": "Use the simple and yet powerful Laravel Blade templating engine as a standalone component.",
|
||||
"keywords": [
|
||||
"blade",
|
||||
"laravel"
|
||||
],
|
||||
"time": "2015-12-04T09:42:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pimple/pimple",
|
||||
"version": "v3.2.3",
|
||||
@ -330,24 +781,121 @@
|
||||
"time": "2016-08-06T14:39:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "slim/php-view",
|
||||
"version": "2.2.0",
|
||||
"name": "psr/log",
|
||||
"version": "1.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/slimphp/PHP-View.git",
|
||||
"reference": "122ed121a8d9cf91a94020814d2a3ee6c836754f"
|
||||
"url": "https://github.com/php-fig/log.git",
|
||||
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/slimphp/PHP-View/zipball/122ed121a8d9cf91a94020814d2a3ee6c836754f",
|
||||
"reference": "122ed121a8d9cf91a94020814d2a3ee6c836754f",
|
||||
"url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
|
||||
"reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Log\\": "Psr/Log/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "http://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for logging libraries",
|
||||
"homepage": "https://github.com/php-fig/log",
|
||||
"keywords": [
|
||||
"log",
|
||||
"psr",
|
||||
"psr-3"
|
||||
],
|
||||
"time": "2016-10-10T12:19:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/simple-cache",
|
||||
"version": "1.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/simple-cache.git",
|
||||
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
|
||||
"reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\SimpleCache\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "http://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interfaces for simple caching",
|
||||
"keywords": [
|
||||
"cache",
|
||||
"caching",
|
||||
"psr",
|
||||
"psr-16",
|
||||
"simple-cache"
|
||||
],
|
||||
"time": "2017-10-23T01:57:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "rubellum/slim-blade-view",
|
||||
"version": "0.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/rubellum/Slim-Blade-View.git",
|
||||
"reference": "9cdea69285acbf712463b38a9bb0b5ce23c4c98c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/rubellum/Slim-Blade-View/zipball/9cdea69285acbf712463b38a9bb0b5ce23c4c98c",
|
||||
"reference": "9cdea69285acbf712463b38a9bb0b5ce23c4c98c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/view": "5.*",
|
||||
"philo/laravel-blade": "3.*",
|
||||
"psr/http-message": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8",
|
||||
"phpunit/phpunit": "^5.0",
|
||||
"slim/slim": "^3.0"
|
||||
},
|
||||
"type": "library",
|
||||
@ -362,21 +910,20 @@
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Glenn Eggleton",
|
||||
"email": "geggleto@gmail.com"
|
||||
"name": "Hiroaki Matsuura",
|
||||
"email": "hiropeke.jp@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Render PHP view scripts into a PSR-7 Response object.",
|
||||
"description": "Slim Framework 3 view helper built on the Blade component",
|
||||
"keywords": [
|
||||
"blade",
|
||||
"framework",
|
||||
"php",
|
||||
"phtml",
|
||||
"renderer",
|
||||
"slim",
|
||||
"template",
|
||||
"view"
|
||||
],
|
||||
"time": "2016-10-11T07:43:08+00:00"
|
||||
"time": "2016-03-11T02:32:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "slim/slim",
|
||||
@ -448,6 +995,238 @@
|
||||
"router"
|
||||
],
|
||||
"time": "2017-11-26T19:13:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/debug",
|
||||
"version": "v4.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/debug.git",
|
||||
"reference": "5961d02d48828671f5d8a7805e06579d692f6ede"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/debug/zipball/5961d02d48828671f5d8a7805e06579d692f6ede",
|
||||
"reference": "5961d02d48828671f5d8a7805e06579d692f6ede",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3",
|
||||
"psr/log": "~1.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/http-kernel": "<3.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/http-kernel": "~3.4|~4.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Debug\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Debug Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-04-03T05:24:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v4.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "ca27c02b7a3fef4828c998c2ff9ba7aae1641c49"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/ca27c02b7a3fef4828c998c2ff9ba7aae1641c49",
|
||||
"reference": "ca27c02b7a3fef4828c998c2ff9ba7aae1641c49",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Finder\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Finder Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-04-04T05:10:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
"version": "v1.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||
"reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b",
|
||||
"reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "For best performance"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Mbstring\\": ""
|
||||
},
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
]
|
||||
},
|
||||
"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": "Symfony polyfill for the Mbstring extension",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"mbstring",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2018-01-30T19:27:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/translation",
|
||||
"version": "v4.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/translation.git",
|
||||
"reference": "e20a9b7f9f62cb33a11638b345c248e7d510c938"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/translation/zipball/e20a9b7f9f62cb33a11638b345c248e7d510c938",
|
||||
"reference": "e20a9b7f9f62cb33a11638b345c248e7d510c938",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.1.3",
|
||||
"symfony/polyfill-mbstring": "~1.0"
|
||||
},
|
||||
"conflict": {
|
||||
"symfony/config": "<3.4",
|
||||
"symfony/dependency-injection": "<3.4",
|
||||
"symfony/yaml": "<3.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"psr/log": "~1.0",
|
||||
"symfony/config": "~3.4|~4.0",
|
||||
"symfony/dependency-injection": "~3.4|~4.0",
|
||||
"symfony/finder": "~2.8|~3.0|~4.0",
|
||||
"symfony/intl": "~3.4|~4.0",
|
||||
"symfony/yaml": "~3.4|~4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/log": "To use logging capability in translator",
|
||||
"symfony/config": "",
|
||||
"symfony/yaml": ""
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Translation\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Translation Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2018-02-22T10:50:29+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
11
controllers/BaseApiController.php
Normal file
11
controllers/BaseApiController.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
class BaseApiController extends BaseController
|
||||
{
|
||||
protected function ApiEncode($response)
|
||||
{
|
||||
return json_encode($response);
|
||||
}
|
||||
}
|
18
controllers/BaseController.php
Normal file
18
controllers/BaseController.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Services\DatabaseService;
|
||||
|
||||
class BaseController
|
||||
{
|
||||
public function __construct(\Slim\Container $container) {
|
||||
$this->AppContainer = $container;
|
||||
|
||||
$databaseService = new DatabaseService();
|
||||
$this->Database = $databaseService->GetDbConnection();
|
||||
}
|
||||
|
||||
protected $AppContainer;
|
||||
protected $Database;
|
||||
}
|
32
controllers/BatteriesApiController.php
Normal file
32
controllers/BatteriesApiController.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Services\BatteriesService;
|
||||
|
||||
class BatteriesApiController extends BaseApiController
|
||||
{
|
||||
public function __construct(\Slim\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
$this->BatteriesService = new BatteriesService();
|
||||
}
|
||||
|
||||
protected $BatteriesService;
|
||||
|
||||
public function TrackChargeCycle($request, $response, $args)
|
||||
{
|
||||
$trackedTime = date('Y-m-d H:i:s');
|
||||
if (isset($request->getQueryParams()['tracked_time']) && !empty($request->getQueryParams()['tracked_time']))
|
||||
{
|
||||
$trackedTime = $request->getQueryParams()['tracked_time'];
|
||||
}
|
||||
|
||||
return $this->ApiEncode(array('success' => $this->BatteriesService->TrackChargeCycle($args['batteryId'], $trackedTime)));
|
||||
}
|
||||
|
||||
public function BatteryDetails($request, $response, $args)
|
||||
{
|
||||
return $this->ApiEncode($this->BatteriesService->GetBatteryDetails($args['batteryId']));
|
||||
}
|
||||
}
|
65
controllers/BatteriesController.php
Normal file
65
controllers/BatteriesController.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Services\BatteriesService;
|
||||
|
||||
class BatteriesController extends BaseController
|
||||
{
|
||||
public function __construct(\Slim\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
$this->BatteriesService = new BatteriesService();
|
||||
}
|
||||
|
||||
protected $BatteriesService;
|
||||
|
||||
public function Overview($request, $response, $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'batteriesoverview', [
|
||||
'title' => 'Batteries overview',
|
||||
'contentPage' => 'batteriesoverview.php',
|
||||
'batteries' => $this->Database->batteries(),
|
||||
'current' => $this->BatteriesService->GetCurrent(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function TrackChargeCycle($request, $response, $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'batterytracking', [
|
||||
'title' => 'Battery tracking',
|
||||
'contentPage' => 'batterytracking.php',
|
||||
'batteries' => $this->Database->batteries()
|
||||
]);
|
||||
}
|
||||
|
||||
public function BatteriesList($request, $response, $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'batteries', [
|
||||
'title' => 'Batteries',
|
||||
'contentPage' => 'batteries.php',
|
||||
'batteries' => $this->Database->batteries()
|
||||
]);
|
||||
}
|
||||
|
||||
public function BatteryEditForm($request, $response, $args)
|
||||
{
|
||||
if ($args['batteryId'] == 'new')
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'batteryform', [
|
||||
'title' => 'Create battery',
|
||||
'contentPage' => 'batteryform.php',
|
||||
'mode' => 'create'
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'batteryform', [
|
||||
'title' => 'Edit battery',
|
||||
'contentPage' => 'batteryform.php',
|
||||
'battery' => $this->Database->batteries($args['batteryId']),
|
||||
'mode' => 'edit'
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
19
controllers/CliController.php
Normal file
19
controllers/CliController.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Services\ApplicationService;
|
||||
use Grocy\Services\DatabaseMigrationService;
|
||||
|
||||
class CliController extends BaseController
|
||||
{
|
||||
public function RecreateDemo($request, $response, $args)
|
||||
{
|
||||
$applicationService = new ApplicationService();
|
||||
if ($applicationService->IsDemoInstallation())
|
||||
{
|
||||
$databaseMigrationService = new DatabaseMigrationService();
|
||||
$databaseMigrationService->RecreateDemo();
|
||||
}
|
||||
}
|
||||
}
|
40
controllers/GenericEntityApiController.php
Normal file
40
controllers/GenericEntityApiController.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
class GenericEntityApiController extends BaseApiController
|
||||
{
|
||||
public function GetObjects($request, $response, $args)
|
||||
{
|
||||
return $this->ApiEncode($this->Database->{$args['entity']}());
|
||||
}
|
||||
|
||||
public function GetObject($request, $response, $args)
|
||||
{
|
||||
return $this->ApiEncode($this->Database->{$args['entity']}($args['objectId']));
|
||||
}
|
||||
|
||||
public function AddObject($request, $response, $args)
|
||||
{
|
||||
$newRow = $this->Database->{$args['entity']}()->createRow($request->getParsedBody());
|
||||
$newRow->save();
|
||||
$success = $newRow->isClean();
|
||||
return $this->ApiEncode(array('success' => $success));
|
||||
}
|
||||
|
||||
public function EditObject($request, $response, $args)
|
||||
{
|
||||
$row = $this->Database->{$args['entity']}($args['objectId']);
|
||||
$row->update($request->getParsedBody());
|
||||
$success = $row->isClean();
|
||||
return $this->ApiEncode(array('success' => $success));
|
||||
}
|
||||
|
||||
public function DeleteObject($request, $response, $args)
|
||||
{
|
||||
$row = $this->Database->{$args['entity']}($args['objectId']);
|
||||
$row->delete();
|
||||
$success = $row->isClean();
|
||||
return $this->ApiEncode(array('success' => $success));
|
||||
}
|
||||
}
|
32
controllers/HabitsApiController.php
Normal file
32
controllers/HabitsApiController.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Services\HabitsService;
|
||||
|
||||
class HabitsApiController extends BaseApiController
|
||||
{
|
||||
public function __construct(\Slim\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
$this->HabitsService = new HabitsService();
|
||||
}
|
||||
|
||||
protected $HabitsService;
|
||||
|
||||
public function TrackHabitExecution($request, $response, $args)
|
||||
{
|
||||
$trackedTime = date('Y-m-d H:i:s');
|
||||
if (isset($request->getQueryParams()['tracked_time']) && !empty($request->getQueryParams()['tracked_time']))
|
||||
{
|
||||
$trackedTime = $request->getQueryParams()['tracked_time'];
|
||||
}
|
||||
|
||||
return $this->ApiEncode(array('success' => $this->HabitsService->TrackHabit($args['habitId'], $trackedTime)));
|
||||
}
|
||||
|
||||
public function HabitDetails($request, $response, $args)
|
||||
{
|
||||
return $this->ApiEncode($this->HabitsService->GetHabitDetails($args['habitId']));
|
||||
}
|
||||
}
|
67
controllers/HabitsController.php
Normal file
67
controllers/HabitsController.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Services\HabitsService;
|
||||
|
||||
class HabitsController extends BaseController
|
||||
{
|
||||
public function __construct(\Slim\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
$this->HabitsService = new HabitsService();
|
||||
}
|
||||
|
||||
protected $HabitsService;
|
||||
|
||||
public function Overview($request, $response, $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'habitsoverview', [
|
||||
'title' => 'Habits overview',
|
||||
'contentPage' => 'habitsoverview.php',
|
||||
'habits' => $this->Database->habits(),
|
||||
'currentHabits' => $this->HabitsService->GetCurrentHabits(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function TrackHabitExecution($request, $response, $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'habittracking', [
|
||||
'title' => 'Habit tracking',
|
||||
'contentPage' => 'habittracking.php',
|
||||
'habits' => $this->Database->habits()
|
||||
]);
|
||||
}
|
||||
|
||||
public function HabitsList($request, $response, $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'habits', [
|
||||
'title' => 'Habits',
|
||||
'contentPage' => 'habits.php',
|
||||
'habits' => $this->Database->habits()
|
||||
]);
|
||||
}
|
||||
|
||||
public function HabitEditForm($request, $response, $args)
|
||||
{
|
||||
if ($args['habitId'] == 'new')
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'habitform', [
|
||||
'title' => 'Create habit',
|
||||
'contentPage' => 'habitform.php',
|
||||
'periodTypes' => GetClassConstants('Grocy\Services\HabitsService'),
|
||||
'mode' => 'create'
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'habitform', [
|
||||
'title' => 'Edit habit',
|
||||
'contentPage' => 'habitform.php',
|
||||
'habit' => $this->Database->habits($args['habitId']),
|
||||
'periodTypes' => GetClassConstants('Grocy\Services\HabitsService'),
|
||||
'mode' => 'edit'
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
73
controllers/LoginController.php
Normal file
73
controllers/LoginController.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Services\SessionService;
|
||||
use Grocy\Services\DatabaseService;
|
||||
use Grocy\Services\ApplicationService;
|
||||
use Grocy\Services\DatabaseMigrationService;
|
||||
use Grocy\Services\DemoDataGeneratorService;
|
||||
|
||||
class LoginController extends BaseController
|
||||
{
|
||||
public function __construct(\Slim\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
$this->SessionService = new SessionService();
|
||||
}
|
||||
|
||||
protected $SessionService;
|
||||
|
||||
public function ProcessLogin($request, $response, $args)
|
||||
{
|
||||
$postParams = $request->getParsedBody();
|
||||
if (isset($postParams['username']) && isset($postParams['password']))
|
||||
{
|
||||
if ($postParams['username'] === HTTP_USER && $postParams['password'] === HTTP_PASSWORD)
|
||||
{
|
||||
$sessionKey = $this->SessionService->CreateSession();
|
||||
setcookie('grocy_session', $sessionKey, time()+2592000); //30 days
|
||||
|
||||
return $response->withRedirect('/');
|
||||
}
|
||||
else
|
||||
{
|
||||
return $response->withRedirect('/login?invalid=true');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return $response->withRedirect('/login?invalid=true');
|
||||
}
|
||||
}
|
||||
|
||||
public function LoginPage($request, $response, $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'login', [
|
||||
'title' => 'Login',
|
||||
'contentPage' => 'login.php'
|
||||
]);
|
||||
}
|
||||
|
||||
public function Logout($request, $response, $args)
|
||||
{
|
||||
$this->SessionService->RemoveSession($_COOKIE['grocy_session']);
|
||||
return $response->withRedirect('/');
|
||||
}
|
||||
|
||||
public function Root($request, $response, $args)
|
||||
{
|
||||
// Schema migration is done here
|
||||
$databaseMigrationService = new DatabaseMigrationService();
|
||||
$databaseMigrationService->MigrateDatabase();
|
||||
|
||||
$applicationService = new ApplicationService();
|
||||
if ($applicationService->IsDemoInstallation())
|
||||
{
|
||||
$demoDataGeneratorService = new DemoDataGeneratorService();
|
||||
$demoDataGeneratorService->PopulateDemoData();
|
||||
}
|
||||
|
||||
return $response->withRedirect('/stockoverview');
|
||||
}
|
||||
}
|
77
controllers/StockApiController.php
Normal file
77
controllers/StockApiController.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Services\StockService;
|
||||
|
||||
class StockApiController extends BaseApiController
|
||||
{
|
||||
public function __construct(\Slim\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
$this->StockService = new StockService();
|
||||
}
|
||||
|
||||
protected $StockService;
|
||||
|
||||
public function ProductDetails($request, $response, $args)
|
||||
{
|
||||
return $this->ApiEncode($this->StockService->GetProductDetails($args['productId']));
|
||||
}
|
||||
|
||||
public function AddProduct($request, $response, $args)
|
||||
{
|
||||
$bestBeforeDate = date('Y-m-d');
|
||||
if (isset($request->getQueryParams()['bestbeforedate']) && !empty($request->getQueryParams()['bestbeforedate']))
|
||||
{
|
||||
$bestBeforeDate = $request->getQueryParams()['bestbeforedate'];
|
||||
}
|
||||
|
||||
$transactionType = StockService::TRANSACTION_TYPE_PURCHASE;
|
||||
if (isset($request->getQueryParams()['transactiontype']) && !empty($request->getQueryParams()['transactiontype']))
|
||||
{
|
||||
$transactionType = $request->getQueryParams()['transactiontype'];
|
||||
}
|
||||
|
||||
return $this->ApiEncode(array('success' => $this->StockService->AddProduct($args['productId'], $args['amount'], $bestBeforeDate, $transactionType)));
|
||||
}
|
||||
|
||||
public function ConsumeProduct($request, $response, $args)
|
||||
{
|
||||
$spoiled = false;
|
||||
if (isset($request->getQueryParams()['spoiled']) && !empty($request->getQueryParams()['spoiled']) && $request->getQueryParams()['spoiled'] == '1')
|
||||
{
|
||||
$spoiled = true;
|
||||
}
|
||||
|
||||
$transactionType = StockService::TRANSACTION_TYPE_CONSUME;
|
||||
if (isset($request->getQueryParams()['transactiontype']) && !empty($request->getQueryParams()['transactiontype']))
|
||||
{
|
||||
$transactionType = $request->getQueryParams()['transactiontype'];
|
||||
}
|
||||
|
||||
return $this->ApiEncode(array('success' => $this->StockService->ConsumeProduct($args['productId'], $args['amount'], $spoiled, $transactionType)));
|
||||
}
|
||||
|
||||
public function InventoryProduct($request, $response, $args)
|
||||
{
|
||||
$bestBeforeDate = date('Y-m-d');
|
||||
if (isset($request->getQueryParams()['bestbeforedate']) && !empty($request->getQueryParams()['bestbeforedate']))
|
||||
{
|
||||
$bestBeforeDate = $request->getQueryParams()['bestbeforedate'];
|
||||
}
|
||||
|
||||
return $this->ApiEncode(array('success' => $this->StockService->InventoryProduct($args['productId'], $args['newAmount'], $bestBeforeDate)));
|
||||
}
|
||||
|
||||
public function CurrentStock($request, $response, $args)
|
||||
{
|
||||
return $this->ApiEncode($this->StockService->GetCurrentStock());
|
||||
}
|
||||
|
||||
public function AddmissingProductsToShoppingList($request, $response, $args)
|
||||
{
|
||||
$this->StockService->AddMissingProductsToShoppingList();
|
||||
return $this->ApiEncode(array('success' => true));
|
||||
}
|
||||
}
|
187
controllers/StockController.php
Normal file
187
controllers/StockController.php
Normal file
@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Services\StockService;
|
||||
|
||||
class StockController extends BaseController
|
||||
{
|
||||
|
||||
public function __construct(\Slim\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
$this->StockService = new StockService();
|
||||
}
|
||||
|
||||
protected $StockService;
|
||||
|
||||
public function Overview($request, $response, $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'stockoverview', [
|
||||
'title' => 'Stock overview',
|
||||
'contentPage' => 'stockoverview.php',
|
||||
'products' => $this->Database->products(),
|
||||
'quantityunits' => $this->Database->quantity_units(),
|
||||
'currentStock' => $this->StockService->GetCurrentStock(),
|
||||
'missingProducts' => $this->StockService->GetMissingProducts()
|
||||
]);
|
||||
}
|
||||
|
||||
public function Purchase($request, $response, $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'purchase', [
|
||||
'title' => 'Purchase',
|
||||
'contentPage' => 'purchase.php',
|
||||
'products' => $this->Database->products()
|
||||
]);
|
||||
}
|
||||
|
||||
public function Consume($request, $response, $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'consume', [
|
||||
'title' => 'Consume',
|
||||
'contentPage' => 'consume.php',
|
||||
'products' => $this->Database->products()
|
||||
]);
|
||||
}
|
||||
|
||||
public function Inventory($request, $response, $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'inventory', [
|
||||
'title' => 'Inventory',
|
||||
'contentPage' => 'inventory.php',
|
||||
'products' => $this->Database->products()
|
||||
]);
|
||||
}
|
||||
|
||||
public function ShoppingList($request, $response, $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'shoppinglist', [
|
||||
'title' => 'Shopping list',
|
||||
'contentPage' => 'shoppinglist.php',
|
||||
'listItems' => $this->Database->shopping_list(),
|
||||
'products' => $this->Database->products(),
|
||||
'quantityunits' => $this->Database->quantity_units(),
|
||||
'missingProducts' => $this->StockService->GetMissingProducts()
|
||||
]);
|
||||
}
|
||||
|
||||
public function ProductsList($request, $response, $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'products', [
|
||||
'title' => 'Products',
|
||||
'contentPage' => 'products.php',
|
||||
'products' => $this->Database->products(),
|
||||
'locations' => $this->Database->locations(),
|
||||
'quantityunits' => $this->Database->quantity_units()
|
||||
]);
|
||||
}
|
||||
|
||||
public function LocationsList($request, $response, $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'locations', [
|
||||
'title' => 'Locations',
|
||||
'contentPage' => 'locations.php',
|
||||
'locations' => $this->Database->locations()
|
||||
]);
|
||||
}
|
||||
|
||||
public function QuantityUnitsList($request, $response, $args)
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'quantityunits', [
|
||||
'title' => 'Quantity units',
|
||||
'contentPage' => 'quantityunits.php',
|
||||
'quantityunits' => $this->Database->quantity_units()
|
||||
]);
|
||||
}
|
||||
|
||||
public function ProductEditForm($request, $response, $args)
|
||||
{
|
||||
if ($args['productId'] == 'new')
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'productform', [
|
||||
'title' => 'Create product',
|
||||
'contentPage' => 'productform.php',
|
||||
'locations' => $this->Database->locations(),
|
||||
'quantityunits' => $this->Database->quantity_units(),
|
||||
'mode' => 'create'
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'productform', [
|
||||
'title' => 'Edit product',
|
||||
'contentPage' => 'productform.php',
|
||||
'product' => $this->Database->products($args['productId']),
|
||||
'locations' => $this->Database->locations(),
|
||||
'quantityunits' => $this->Database->quantity_units(),
|
||||
'mode' => 'edit'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function LocationEditForm($request, $response, $args)
|
||||
{
|
||||
if ($args['locationId'] == 'new')
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'locationform', [
|
||||
'title' => 'Create location',
|
||||
'contentPage' => 'locationform.php',
|
||||
'mode' => 'create'
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'locationform', [
|
||||
'title' => 'Edit location',
|
||||
'contentPage' => 'locationform.php',
|
||||
'location' => $this->Database->locations($args['locationId']),
|
||||
'mode' => 'edit'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function QuantityUnitEditForm($request, $response, $args)
|
||||
{
|
||||
if ($args['quantityunitId'] == 'new')
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'quantityunitform', [
|
||||
'title' => 'Create quantity unit',
|
||||
'contentPage' => 'quantityunitform.php',
|
||||
'mode' => 'create'
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'quantityunitform', [
|
||||
'title' => 'Edit quantity unit',
|
||||
'contentPage' => 'quantityunitform.php',
|
||||
'quantityunit' => $this->Database->quantity_units($args['quantityunitId']),
|
||||
'mode' => 'edit'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function ShoppingListItemEditForm($request, $response, $args)
|
||||
{
|
||||
if ($args['itemId'] == 'new')
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'shoppinglistform', [
|
||||
'title' => 'Add shopping list item',
|
||||
'contentPage' => 'shoppinglistform.php',
|
||||
'products' => $this->Database->products(),
|
||||
'mode' => 'create'
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->AppContainer->view->render($response, 'shoppinglistform', [
|
||||
'title' => 'Edit shopping list item',
|
||||
'contentPage' => 'shoppinglistform.php',
|
||||
'listItem' => $this->Database->shopping_list($args['itemId']),
|
||||
'products' => $this->Database->products(),
|
||||
'mode' => 'edit'
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
1
data/.gitignore
vendored
1
data/.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
*
|
||||
!.gitignore
|
||||
!viewcache
|
||||
|
2
data/viewcache/.gitignore
vendored
Normal file
2
data/viewcache/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
63
extensions.php
Normal file
63
extensions.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
function FindObjectInArrayByPropertyValue($array, $propertyName, $propertyValue)
|
||||
{
|
||||
foreach($array as $object)
|
||||
{
|
||||
if($object->{$propertyName} == $propertyValue)
|
||||
{
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function FindAllObjectsInArrayByPropertyValue($array, $propertyName, $propertyValue, $operator = '==')
|
||||
{
|
||||
$returnArray = array();
|
||||
|
||||
foreach($array as $object)
|
||||
{
|
||||
switch($operator)
|
||||
{
|
||||
case '==':
|
||||
if($object->{$propertyName} == $propertyValue)
|
||||
{
|
||||
$returnArray[] = $object;
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
if($object->{$propertyName} > $propertyValue)
|
||||
{
|
||||
$returnArray[] = $object;
|
||||
}
|
||||
break;
|
||||
case '<':
|
||||
if($object->{$propertyName} < $propertyValue)
|
||||
{
|
||||
$returnArray[] = $object;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $returnArray;
|
||||
}
|
||||
|
||||
function SumArrayValue($array, $propertyName)
|
||||
{
|
||||
$sum = 0;
|
||||
foreach($array as $object)
|
||||
{
|
||||
$sum += $object->{$propertyName};
|
||||
}
|
||||
|
||||
return $sum;
|
||||
}
|
||||
|
||||
function GetClassConstants($className)
|
||||
{
|
||||
$r = new ReflectionClass($className);
|
||||
return $r->getConstants();
|
||||
}
|
581
index.php
581
index.php
@ -2,22 +2,19 @@
|
||||
|
||||
use \Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use \Psr\Http\Message\ResponseInterface as Response;
|
||||
use Slim\Views\PhpRenderer;
|
||||
|
||||
use Grocy\Middleware\SessionMiddleware;
|
||||
use Grocy\Middleware\JsonMiddleware;
|
||||
use Grocy\Middleware\CliMiddleware;
|
||||
|
||||
use Grocy\Services\ApplicationService;
|
||||
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
require_once __DIR__ . '/data/config.php';
|
||||
require_once __DIR__ . '/services/ApplicationService.php';
|
||||
require_once __DIR__ . '/services/DatabaseService.php';
|
||||
require_once __DIR__ . '/services/SessionService.php';
|
||||
require_once __DIR__ . '/GrocyDbMigrator.php';
|
||||
require_once __DIR__ . '/GrocyDemoDataGenerator.php';
|
||||
require_once __DIR__ . '/services/StockService.php';
|
||||
require_once __DIR__ . '/services/HabitsService.php';
|
||||
require_once __DIR__ . '/services/BatteriesService.php';
|
||||
require_once __DIR__ . '/GrocyPhpHelper.php';
|
||||
require_once __DIR__ . '/extensions.php';
|
||||
|
||||
// Setup base application
|
||||
$app = new \Slim\App;
|
||||
|
||||
if (PHP_SAPI !== 'cli')
|
||||
{
|
||||
$app = new \Slim\App(new \Slim\Container([
|
||||
@ -26,508 +23,92 @@ if (PHP_SAPI !== 'cli')
|
||||
'determineRouteBeforeAppMiddleware' => true
|
||||
],
|
||||
]));
|
||||
|
||||
$container = $app->getContainer();
|
||||
$container['renderer'] = new PhpRenderer('./views');
|
||||
}
|
||||
|
||||
if (PHP_SAPI === 'cli')
|
||||
{
|
||||
$app->add(new \pavlakis\cli\CliRequest());
|
||||
}
|
||||
|
||||
if (!ApplicationService::IsDemoInstallation())
|
||||
{
|
||||
$sessionMiddleware = function(Request $request, Response $response, callable $next)
|
||||
$container['view'] = function($container)
|
||||
{
|
||||
$route = $request->getAttribute('route');
|
||||
$routeName = $route->getName();
|
||||
|
||||
if ((!isset($_COOKIE['grocy_session']) || !SessionService::IsValidSession($_COOKIE['grocy_session'])) && $routeName !== 'login')
|
||||
{
|
||||
$response = $response->withRedirect('/login');
|
||||
}
|
||||
else
|
||||
{
|
||||
$response = $next($request, $response);
|
||||
}
|
||||
|
||||
return $response;
|
||||
return new \Slim\Views\Blade(__DIR__ . '/views', __DIR__ . '/data/viewcache');
|
||||
};
|
||||
|
||||
$app->add($sessionMiddleware);
|
||||
}
|
||||
else
|
||||
{
|
||||
$app->add(\pavlakis\cli\CliRequest::class);
|
||||
}
|
||||
|
||||
$db = DatabaseService::GetDbConnection();
|
||||
|
||||
$app->get('/login', function(Request $request, Response $response)
|
||||
// Add session handling if this is not a demo installation
|
||||
$applicationService = new ApplicationService();
|
||||
if (!$applicationService->IsDemoInstallation())
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Login',
|
||||
'contentPage' => 'login.php'
|
||||
]);
|
||||
})->setName('login');
|
||||
$app->add(SessionMiddleware::class);
|
||||
}
|
||||
|
||||
$app->post('/login', function(Request $request, Response $response)
|
||||
// Base route
|
||||
$app->get('/', 'Grocy\Controllers\LoginController:Root');
|
||||
|
||||
// Login routes
|
||||
$app->get('/login', 'Grocy\Controllers\LoginController:LoginPage')->setName('login');
|
||||
$app->post('/login', 'Grocy\Controllers\LoginController:ProcessLogin')->setName('login');
|
||||
$app->get('/logout', 'Grocy\Controllers\LoginController:Logout');
|
||||
|
||||
// Stock routes
|
||||
$app->get('/stockoverview', 'Grocy\Controllers\StockController:Overview');
|
||||
$app->get('/purchase', 'Grocy\Controllers\StockController:Purchase');
|
||||
$app->get('/consume', 'Grocy\Controllers\StockController:Consume');
|
||||
$app->get('/inventory', 'Grocy\Controllers\StockController:Inventory');
|
||||
|
||||
$app->get('/products', 'Grocy\Controllers\StockController:ProductsList');
|
||||
$app->get('/product/{productId}', 'Grocy\Controllers\StockController:ProductEditForm');
|
||||
|
||||
$app->get('/locations', 'Grocy\Controllers\StockController:LocationsList');
|
||||
$app->get('/location/{locationId}', 'Grocy\Controllers\StockController:LocationEditForm');
|
||||
|
||||
$app->get('/quantityunits', 'Grocy\Controllers\StockController:QuantityUnitsList');
|
||||
$app->get('/quantityunit/{quantityunitId}', 'Grocy\Controllers\StockController:QuantityUnitEditForm');
|
||||
|
||||
$app->get('/shoppinglist', 'Grocy\Controllers\StockController:ShoppingList');
|
||||
$app->get('/shoppinglistitem/{itemId}', 'Grocy\Controllers\StockController:ShoppingListItemEditForm');
|
||||
|
||||
|
||||
// Habit routes
|
||||
$app->get('/habitsoverview', 'Grocy\Controllers\HabitsController:Overview');
|
||||
$app->get('/habittracking', 'Grocy\Controllers\HabitsController:TrackHabitExecution');
|
||||
|
||||
$app->get('/habits', 'Grocy\Controllers\HabitsController:HabitsList');
|
||||
$app->get('/habit/{habitId}', 'Grocy\Controllers\HabitsController:HabitEditForm');
|
||||
|
||||
// Batterry routes
|
||||
$app->get('/batteriesoverview', 'Grocy\Controllers\BatteriesController:Overview');
|
||||
$app->get('/batterytracking', 'Grocy\Controllers\BatteriesController:TrackChargeCycle');
|
||||
|
||||
$app->get('/batteries', 'Grocy\Controllers\BatteriesController:BatteriesList');
|
||||
$app->get('/battery/{batteryId}', 'Grocy\Controllers\BatteriesController:BatteryEditForm');
|
||||
|
||||
|
||||
$app->group('/api', function()
|
||||
{
|
||||
$postParams = $request->getParsedBody();
|
||||
if (isset($postParams['username']) && isset($postParams['password']))
|
||||
{
|
||||
if ($postParams['username'] === HTTP_USER && $postParams['password'] === HTTP_PASSWORD)
|
||||
{
|
||||
$sessionKey = SessionService::CreateSession();
|
||||
setcookie('grocy_session', $sessionKey, time()+2592000); //30 days
|
||||
$this->get('/get-objects/{entity}', 'Grocy\Controllers\GenericEntityApiController:GetObjects');
|
||||
$this->get('/get-object/{entity}/{objectId}', 'Grocy\Controllers\GenericEntityApiController:GetObject');
|
||||
$this->post('/add-object/{entity}', 'Grocy\Controllers\GenericEntityApiController:AddObject');
|
||||
$this->post('/edit-object/{entity}/{objectId}', 'Grocy\Controllers\GenericEntityApiController:EditObject');
|
||||
$this->get('/delete-object/{entity}/{objectId}', 'Grocy\Controllers\GenericEntityApiController:DeleteObject');
|
||||
|
||||
return $response->withRedirect('/');
|
||||
}
|
||||
else
|
||||
{
|
||||
return $response->withRedirect('/login?invalid=true');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return $response->withRedirect('/login?invalid=true');
|
||||
}
|
||||
})->setName('login');
|
||||
$this->get('/stock/add-product/{productId}/{amount}', 'Grocy\Controllers\StockApiController:AddProduct');
|
||||
$this->get('/stock/consume-product/{productId}/{amount}', 'Grocy\Controllers\StockApiController:ConsumeProduct');
|
||||
$this->get('/stock/inventory-product/{productId}/{newAmount}', 'Grocy\Controllers\StockApiController:InventoryProduct');
|
||||
$this->get('/stock/get-product-details/{productId}', 'Grocy\Controllers\StockApiController:ProductDetails');
|
||||
$this->get('/stock/get-current-stock', 'Grocy\Controllers\StockApiController:CurrentStock');
|
||||
$this->get('/stock/add-missing-products-to-shoppinglist', 'Grocy\Controllers\StockApiController:AddMissingProductsToShoppingList');
|
||||
|
||||
$app->get('/logout', function(Request $request, Response $response)
|
||||
{
|
||||
SessionService::RemoveSession($_COOKIE['grocy_session']);
|
||||
return $response->withRedirect('/');
|
||||
});
|
||||
$this->get('/habits/track-habit-execution/{habitId}', 'Grocy\Controllers\HabitsApiController:TrackHabitExecution');
|
||||
$this->get('/habits/get-habit-details/{habitId}', 'Grocy\Controllers\HabitsApiController:HabitDetails');
|
||||
|
||||
$app->get('/', function(Request $request, Response $response) use($db)
|
||||
{
|
||||
$db = DatabaseService::GetDbConnection(true); //For database schema migration
|
||||
|
||||
return $response->withRedirect('/stockoverview');
|
||||
});
|
||||
|
||||
$app->get('/stockoverview', function(Request $request, Response $response) use($db)
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Stock overview',
|
||||
'contentPage' => 'stockoverview.php',
|
||||
'products' => $db->products(),
|
||||
'quantityunits' => $db->quantity_units(),
|
||||
'currentStock' => StockService::GetCurrentStock(),
|
||||
'missingProducts' => StockService::GetMissingProducts()
|
||||
]);
|
||||
});
|
||||
|
||||
$app->get('/habitsoverview', function(Request $request, Response $response) use($db)
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Habits overview',
|
||||
'contentPage' => 'habitsoverview.php',
|
||||
'habits' => $db->habits(),
|
||||
'currentHabits' => HabitsService::GetCurrentHabits(),
|
||||
]);
|
||||
});
|
||||
|
||||
$app->get('/batteriesoverview', function(Request $request, Response $response) use($db)
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Batteries overview',
|
||||
'contentPage' => 'batteriesoverview.php',
|
||||
'batteries' => $db->batteries(),
|
||||
'current' => BatteriesService::GetCurrent(),
|
||||
]);
|
||||
});
|
||||
|
||||
$app->get('/purchase', function(Request $request, Response $response) use($db)
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Purchase',
|
||||
'contentPage' => 'purchase.php',
|
||||
'products' => $db->products()
|
||||
]);
|
||||
});
|
||||
|
||||
$app->get('/consume', function(Request $request, Response $response) use($db)
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Consume',
|
||||
'contentPage' => 'consume.php',
|
||||
'products' => $db->products()
|
||||
]);
|
||||
});
|
||||
|
||||
$app->get('/inventory', function(Request $request, Response $response) use($db)
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Inventory',
|
||||
'contentPage' => 'inventory.php',
|
||||
'products' => $db->products()
|
||||
]);
|
||||
});
|
||||
|
||||
$app->get('/shoppinglist', function(Request $request, Response $response) use($db)
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Shopping list',
|
||||
'contentPage' => 'shoppinglist.php',
|
||||
'listItems' => $db->shopping_list(),
|
||||
'products' => $db->products(),
|
||||
'quantityunits' => $db->quantity_units(),
|
||||
'missingProducts' => StockService::GetMissingProducts()
|
||||
]);
|
||||
});
|
||||
|
||||
$app->get('/habittracking', function(Request $request, Response $response) use($db)
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Habit tracking',
|
||||
'contentPage' => 'habittracking.php',
|
||||
'habits' => $db->habits()
|
||||
]);
|
||||
});
|
||||
|
||||
$app->get('/batterytracking', function(Request $request, Response $response) use($db)
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Battery tracking',
|
||||
'contentPage' => 'batterytracking.php',
|
||||
'batteries' => $db->batteries()
|
||||
]);
|
||||
});
|
||||
|
||||
$app->get('/products', function(Request $request, Response $response) use($db)
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Products',
|
||||
'contentPage' => 'products.php',
|
||||
'products' => $db->products(),
|
||||
'locations' => $db->locations(),
|
||||
'quantityunits' => $db->quantity_units()
|
||||
]);
|
||||
});
|
||||
|
||||
$app->get('/locations', function(Request $request, Response $response) use($db)
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Locations',
|
||||
'contentPage' => 'locations.php',
|
||||
'locations' => $db->locations()
|
||||
]);
|
||||
});
|
||||
|
||||
$app->get('/quantityunits', function(Request $request, Response $response) use($db)
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Quantity units',
|
||||
'contentPage' => 'quantityunits.php',
|
||||
'quantityunits' => $db->quantity_units()
|
||||
]);
|
||||
});
|
||||
|
||||
$app->get('/habits', function(Request $request, Response $response) use($db)
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Habits',
|
||||
'contentPage' => 'habits.php',
|
||||
'habits' => $db->habits()
|
||||
]);
|
||||
});
|
||||
|
||||
$app->get('/batteries', function(Request $request, Response $response) use($db)
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Batteries',
|
||||
'contentPage' => 'batteries.php',
|
||||
'batteries' => $db->batteries()
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
$app->get('/product/{productId}', function(Request $request, Response $response, $args) use($db)
|
||||
{
|
||||
if ($args['productId'] == 'new')
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Create product',
|
||||
'contentPage' => 'productform.php',
|
||||
'locations' => $db->locations(),
|
||||
'quantityunits' => $db->quantity_units(),
|
||||
'mode' => 'create'
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Edit product',
|
||||
'contentPage' => 'productform.php',
|
||||
'product' => $db->products($args['productId']),
|
||||
'locations' => $db->locations(),
|
||||
'quantityunits' => $db->quantity_units(),
|
||||
'mode' => 'edit'
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
$app->get('/location/{locationId}', function(Request $request, Response $response, $args) use($db)
|
||||
{
|
||||
if ($args['locationId'] == 'new')
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Create location',
|
||||
'contentPage' => 'locationform.php',
|
||||
'mode' => 'create'
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Edit location',
|
||||
'contentPage' => 'locationform.php',
|
||||
'location' => $db->locations($args['locationId']),
|
||||
'mode' => 'edit'
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
$app->get('/quantityunit/{quantityunitId}', function(Request $request, Response $response, $args) use($db)
|
||||
{
|
||||
if ($args['quantityunitId'] == 'new')
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Create quantity unit',
|
||||
'contentPage' => 'quantityunitform.php',
|
||||
'mode' => 'create'
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Edit quantity unit',
|
||||
'contentPage' => 'quantityunitform.php',
|
||||
'quantityunit' => $db->quantity_units($args['quantityunitId']),
|
||||
'mode' => 'edit'
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
$app->get('/habit/{habitId}', function(Request $request, Response $response, $args) use($db)
|
||||
{
|
||||
if ($args['habitId'] == 'new')
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Create habit',
|
||||
'contentPage' => 'habitform.php',
|
||||
'periodTypes' => GrocyPhpHelper::GetClassConstants('HabitsService'),
|
||||
'mode' => 'create'
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Edit habit',
|
||||
'contentPage' => 'habitform.php',
|
||||
'habit' => $db->habits($args['habitId']),
|
||||
'periodTypes' => GrocyPhpHelper::GetClassConstants('HabitsService'),
|
||||
'mode' => 'edit'
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
$app->get('/battery/{batteryId}', function(Request $request, Response $response, $args) use($db)
|
||||
{
|
||||
if ($args['batteryId'] == 'new')
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Create battery',
|
||||
'contentPage' => 'batteryform.php',
|
||||
'mode' => 'create'
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Edit battery',
|
||||
'contentPage' => 'batteryform.php',
|
||||
'battery' => $db->batteries($args['batteryId']),
|
||||
'mode' => 'edit'
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
$app->get('/shoppinglistitem/{itemId}', function(Request $request, Response $response, $args) use($db)
|
||||
{
|
||||
if ($args['itemId'] == 'new')
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Add shopping list item',
|
||||
'contentPage' => 'shoppinglistform.php',
|
||||
'products' => $db->products(),
|
||||
'mode' => 'create'
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->renderer->render($response, 'layout/default.php', [
|
||||
'title' => 'Edit shopping list item',
|
||||
'contentPage' => 'shoppinglistform.php',
|
||||
'listItem' => $db->shopping_list($args['itemId']),
|
||||
'products' => $db->products(),
|
||||
'mode' => 'edit'
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
$app->group('/api', function() use($db)
|
||||
{
|
||||
$this->get('/get-objects/{entity}', function(Request $request, Response $response, $args) use($db)
|
||||
{
|
||||
echo json_encode($db->{$args['entity']}());
|
||||
});
|
||||
|
||||
$this->get('/get-object/{entity}/{objectId}', function(Request $request, Response $response, $args) use($db)
|
||||
{
|
||||
echo json_encode($db->{$args['entity']}($args['objectId']));
|
||||
});
|
||||
|
||||
$this->post('/add-object/{entity}', function(Request $request, Response $response, $args) use($db)
|
||||
{
|
||||
$newRow = $db->{$args['entity']}()->createRow($request->getParsedBody());
|
||||
$newRow->save();
|
||||
$success = $newRow->isClean();
|
||||
echo json_encode(array('success' => $success));
|
||||
});
|
||||
|
||||
$this->post('/edit-object/{entity}/{objectId}', function(Request $request, Response $response, $args) use($db)
|
||||
{
|
||||
$row = $db->{$args['entity']}($args['objectId']);
|
||||
$row->update($request->getParsedBody());
|
||||
$success = $row->isClean();
|
||||
echo json_encode(array('success' => $success));
|
||||
});
|
||||
|
||||
$this->get('/delete-object/{entity}/{objectId}', function(Request $request, Response $response, $args) use($db)
|
||||
{
|
||||
$row = $db->{$args['entity']}($args['objectId']);
|
||||
$row->delete();
|
||||
$success = $row->isClean();
|
||||
echo json_encode(array('success' => $success));
|
||||
});
|
||||
|
||||
$this->get('/stock/add-product/{productId}/{amount}', function(Request $request, Response $response, $args)
|
||||
{
|
||||
$bestBeforeDate = date('Y-m-d');
|
||||
if (isset($request->getQueryParams()['bestbeforedate']) && !empty($request->getQueryParams()['bestbeforedate']))
|
||||
{
|
||||
$bestBeforeDate = $request->getQueryParams()['bestbeforedate'];
|
||||
}
|
||||
|
||||
$transactionType = StockService::TRANSACTION_TYPE_PURCHASE;
|
||||
if (isset($request->getQueryParams()['transactiontype']) && !empty($request->getQueryParams()['transactiontype']))
|
||||
{
|
||||
$transactionType = $request->getQueryParams()['transactiontype'];
|
||||
}
|
||||
|
||||
echo json_encode(array('success' => StockService::AddProduct($args['productId'], $args['amount'], $bestBeforeDate, $transactionType)));
|
||||
});
|
||||
|
||||
$this->get('/stock/consume-product/{productId}/{amount}', function(Request $request, Response $response, $args)
|
||||
{
|
||||
$spoiled = false;
|
||||
if (isset($request->getQueryParams()['spoiled']) && !empty($request->getQueryParams()['spoiled']) && $request->getQueryParams()['spoiled'] == '1')
|
||||
{
|
||||
$spoiled = true;
|
||||
}
|
||||
|
||||
$transactionType = StockService::TRANSACTION_TYPE_CONSUME;
|
||||
if (isset($request->getQueryParams()['transactiontype']) && !empty($request->getQueryParams()['transactiontype']))
|
||||
{
|
||||
$transactionType = $request->getQueryParams()['transactiontype'];
|
||||
}
|
||||
|
||||
echo json_encode(array('success' => StockService::ConsumeProduct($args['productId'], $args['amount'], $spoiled, $transactionType)));
|
||||
});
|
||||
|
||||
$this->get('/stock/inventory-product/{productId}/{newAmount}', function(Request $request, Response $response, $args)
|
||||
{
|
||||
$bestBeforeDate = date('Y-m-d');
|
||||
if (isset($request->getQueryParams()['bestbeforedate']) && !empty($request->getQueryParams()['bestbeforedate']))
|
||||
{
|
||||
$bestBeforeDate = $request->getQueryParams()['bestbeforedate'];
|
||||
}
|
||||
|
||||
echo json_encode(array('success' => StockService::InventoryProduct($args['productId'], $args['newAmount'], $bestBeforeDate)));
|
||||
});
|
||||
|
||||
$this->get('/stock/get-product-details/{productId}', function(Request $request, Response $response, $args)
|
||||
{
|
||||
echo json_encode(StockService::GetProductDetails($args['productId']));
|
||||
});
|
||||
|
||||
$this->get('/stock/get-current-stock', function(Request $request, Response $response)
|
||||
{
|
||||
echo json_encode(StockService::GetCurrentStock());
|
||||
});
|
||||
|
||||
$this->get('/stock/add-missing-products-to-shoppinglist', function(Request $request, Response $response)
|
||||
{
|
||||
StockService::AddMissingProductsToShoppingList();
|
||||
echo json_encode(array('success' => true));
|
||||
});
|
||||
|
||||
$this->get('/habits/track-habit/{habitId}', function(Request $request, Response $response, $args)
|
||||
{
|
||||
$trackedTime = date('Y-m-d H:i:s');
|
||||
if (isset($request->getQueryParams()['tracked_time']) && !empty($request->getQueryParams()['tracked_time']))
|
||||
{
|
||||
$trackedTime = $request->getQueryParams()['tracked_time'];
|
||||
}
|
||||
|
||||
echo json_encode(array('success' => HabitsService::TrackHabit($args['habitId'], $trackedTime)));
|
||||
});
|
||||
|
||||
$this->get('/habits/get-habit-details/{habitId}', function(Request $request, Response $response, $args)
|
||||
{
|
||||
echo json_encode(HabitsService::GetHabitDetails($args['habitId']));
|
||||
});
|
||||
|
||||
$this->get('/batteries/track-charge-cycle/{batteryId}', function(Request $request, Response $response, $args)
|
||||
{
|
||||
$trackedTime = date('Y-m-d H:i:s');
|
||||
if (isset($request->getQueryParams()['tracked_time']) && !empty($request->getQueryParams()['tracked_time']))
|
||||
{
|
||||
$trackedTime = $request->getQueryParams()['tracked_time'];
|
||||
}
|
||||
|
||||
echo json_encode(array('success' => BatteriesService::TrackChargeCycle($args['batteryId'], $trackedTime)));
|
||||
});
|
||||
|
||||
$this->get('/batteries/get-battery-details/{batteryId}', function(Request $request, Response $response, $args)
|
||||
{
|
||||
echo json_encode(BatteriesService::GetBatteryDetails($args['batteryId']));
|
||||
});
|
||||
})->add(function($request, $response, $next)
|
||||
{
|
||||
$response = $next($request, $response);
|
||||
return $response->withHeader('Content-Type', 'application/json');
|
||||
});
|
||||
$this->get('/batteries/track-charge-cycle/{batteryId}', 'Grocy\Controllers\BatteriesApiController:TrackChargeCycle');
|
||||
$this->get('/batteries/get-battery-details/{batteryId}', 'Grocy\Controllers\BatteriesApiController:BatteryDetails');
|
||||
})->add(JsonMiddleware::class);
|
||||
|
||||
$app->group('/cli', function()
|
||||
{
|
||||
$this->get('/recreatedemo', function(Request $request, Response $response)
|
||||
{
|
||||
if (ApplicationService::IsDemoInstallation())
|
||||
{
|
||||
GrocyDemoDataGenerator::RecreateDemo();
|
||||
}
|
||||
});
|
||||
})->add(function($request, $response, $next)
|
||||
{
|
||||
$response = $next($request, $response);
|
||||
|
||||
if (PHP_SAPI !== 'cli')
|
||||
{
|
||||
echo 'Please call this only from CLI';
|
||||
return $response->withHeader('Content-Type', 'text/plain')->withStatus(400);
|
||||
}
|
||||
|
||||
return $response->withHeader('Content-Type', 'text/plain');
|
||||
});
|
||||
$this->get('/recreatedemo', 'Grocy\Controllers\CliController:RecreateDemo');
|
||||
})->add(CliMiddleware::class);
|
||||
|
||||
$app->run();
|
||||
|
25
middleware/CliMiddleware.php
Normal file
25
middleware/CliMiddleware.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Middleware;
|
||||
|
||||
class CliMiddleware
|
||||
{
|
||||
public function __construct(\Slim\Container $container) {
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
protected $container;
|
||||
|
||||
public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next)
|
||||
{
|
||||
$response = $next($request, $response);
|
||||
|
||||
if (PHP_SAPI !== 'cli')
|
||||
{
|
||||
$response->write('Please call this only from CLI');
|
||||
return $response->withHeader('Content-Type', 'text/plain')->withStatus(400);
|
||||
}
|
||||
|
||||
return $response->withHeader('Content-Type', 'text/plain');
|
||||
}
|
||||
}
|
18
middleware/JsonMiddleware.php
Normal file
18
middleware/JsonMiddleware.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Middleware;
|
||||
|
||||
class JsonMiddleware
|
||||
{
|
||||
public function __construct(\Slim\Container $container) {
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
protected $container;
|
||||
|
||||
public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next)
|
||||
{
|
||||
$response = $next($request, $response, $next);
|
||||
return $response->withHeader('Content-Type', 'application/json');
|
||||
}
|
||||
}
|
32
middleware/SessionMiddleware.php
Normal file
32
middleware/SessionMiddleware.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Middleware;
|
||||
|
||||
use Grocy\Services\SessionService;
|
||||
|
||||
class SessionMiddleware
|
||||
{
|
||||
public function __construct(\Slim\Container $container) {
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
protected $container;
|
||||
|
||||
public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next)
|
||||
{
|
||||
$route = $request->getAttribute('route');
|
||||
$routeName = $route->getName();
|
||||
|
||||
$sessionService = new SessionService();
|
||||
if ((!isset($_COOKIE['grocy_session']) || !$sessionService->IsValidSession($_COOKIE['grocy_session'])) && $routeName !== 'login')
|
||||
{
|
||||
$response = $response->withRedirect('/login');
|
||||
}
|
||||
else
|
||||
{
|
||||
$response = $next($request, $response);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
@ -1,26 +1,28 @@
|
||||
<?php
|
||||
|
||||
class ApplicationService
|
||||
namespace Grocy\Services;
|
||||
|
||||
class ApplicationService extends BaseService
|
||||
{
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public static function IsDemoInstallation()
|
||||
public function IsDemoInstallation()
|
||||
{
|
||||
return file_exists(__DIR__ . '/../data/demo.txt');
|
||||
}
|
||||
|
||||
private static $InstalledVersion;
|
||||
private $InstalledVersion;
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function GetInstalledVersion()
|
||||
public function GetInstalledVersion()
|
||||
{
|
||||
if (self::$InstalledVersion == null)
|
||||
if ($this->InstalledVersion == null)
|
||||
{
|
||||
self::$InstalledVersion = preg_replace("/\r|\n/", '', file_get_contents(__DIR__ . '/../version.txt'));
|
||||
$this->InstalledVersion = preg_replace("/\r|\n/", '', file_get_contents(__DIR__ . '/../version.txt'));
|
||||
}
|
||||
|
||||
return self::$InstalledVersion;
|
||||
return $this->InstalledVersion;
|
||||
}
|
||||
}
|
||||
|
16
services/BaseService.php
Normal file
16
services/BaseService.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Services;
|
||||
|
||||
use Grocy\Services\DatabaseService;
|
||||
|
||||
class BaseService
|
||||
{
|
||||
public function __construct() {
|
||||
$this->DatabaseService = new DatabaseService();
|
||||
$this->Database = $this->DatabaseService->GetDbConnection();
|
||||
}
|
||||
|
||||
protected $DatabaseService;
|
||||
protected $Database;
|
||||
}
|
@ -1,19 +1,19 @@
|
||||
<?php
|
||||
|
||||
class BatteriesService
|
||||
namespace Grocy\Services;
|
||||
|
||||
class BatteriesService extends BaseService
|
||||
{
|
||||
public static function GetCurrent()
|
||||
public function GetCurrent()
|
||||
{
|
||||
$sql = 'SELECT * from batteries_current';
|
||||
return DatabaseService::ExecuteDbQuery(DatabaseService::GetDbConnectionRaw(), $sql)->fetchAll(PDO::FETCH_OBJ);
|
||||
return $this->DatabaseService->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
|
||||
}
|
||||
|
||||
public static function GetNextChargeTime(int $batteryId)
|
||||
public function GetNextChargeTime(int $batteryId)
|
||||
{
|
||||
$db = DatabaseService::GetDbConnection();
|
||||
|
||||
$battery = $db->batteries($batteryId);
|
||||
$batteryLastLogRow = DatabaseService::ExecuteDbQuery(DatabaseService::GetDbConnectionRaw(), "SELECT * from batteries_current WHERE battery_id = $batteryId LIMIT 1")->fetch(PDO::FETCH_OBJ);
|
||||
$battery = $this->Database->batteries($batteryId);
|
||||
$batteryLastLogRow = $this->DatabaseService->ExecuteDbQuery("SELECT * from batteries_current WHERE battery_id = $batteryId LIMIT 1")->fetch(\PDO::FETCH_OBJ);
|
||||
|
||||
if ($battery->charge_interval_days > 0)
|
||||
{
|
||||
@ -27,13 +27,11 @@ class BatteriesService
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function GetBatteryDetails(int $batteryId)
|
||||
public function GetBatteryDetails(int $batteryId)
|
||||
{
|
||||
$db = DatabaseService::GetDbConnection();
|
||||
|
||||
$battery = $db->batteries($batteryId);
|
||||
$batteryChargeCylcesCount = $db->battery_charge_cycles()->where('battery_id', $batteryId)->count();
|
||||
$batteryLastChargedTime = $db->battery_charge_cycles()->where('battery_id', $batteryId)->max('tracked_time');
|
||||
$battery = $this->Database->batteries($batteryId);
|
||||
$batteryChargeCylcesCount = $this->Database->battery_charge_cycles()->where('battery_id', $batteryId)->count();
|
||||
$batteryLastChargedTime = $this->Database->battery_charge_cycles()->where('battery_id', $batteryId)->max('tracked_time');
|
||||
|
||||
return array(
|
||||
'battery' => $battery,
|
||||
@ -42,11 +40,9 @@ class BatteriesService
|
||||
);
|
||||
}
|
||||
|
||||
public static function TrackChargeCycle(int $batteryId, string $trackedTime)
|
||||
public function TrackChargeCycle(int $batteryId, string $trackedTime)
|
||||
{
|
||||
$db = DatabaseService::GetDbConnection();
|
||||
|
||||
$logRow = $db->battery_charge_cycles()->createRow(array(
|
||||
$logRow = $this->Database->battery_charge_cycles()->createRow(array(
|
||||
'battery_id' => $batteryId,
|
||||
'tracked_time' => $trackedTime
|
||||
));
|
||||
|
@ -1,10 +1,14 @@
|
||||
<?php
|
||||
|
||||
class GrocyDbMigrator
|
||||
namespace Grocy\Services;
|
||||
|
||||
class DatabaseMigrationService extends BaseService
|
||||
{
|
||||
public static function MigrateDb(PDO $pdo)
|
||||
public function MigrateDatabase()
|
||||
{
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 1, "
|
||||
$this->DatabaseService->ExecuteDbStatement("CREATE TABLE IF NOT EXISTS migrations (migration INTEGER NOT NULL PRIMARY KEY UNIQUE, execution_time_timestamp DATETIME DEFAULT (datetime('now', 'localtime')))");
|
||||
|
||||
$this->ExecuteMigrationWhenNeeded(1, "
|
||||
CREATE TABLE products (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
@ -20,7 +24,7 @@ class GrocyDbMigrator
|
||||
)"
|
||||
);
|
||||
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 2, "
|
||||
$this->ExecuteMigrationWhenNeeded(2, "
|
||||
CREATE TABLE locations (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
@ -29,7 +33,7 @@ class GrocyDbMigrator
|
||||
)"
|
||||
);
|
||||
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 3, "
|
||||
$this->ExecuteMigrationWhenNeeded(3, "
|
||||
CREATE TABLE quantity_units (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
@ -38,7 +42,7 @@ class GrocyDbMigrator
|
||||
)"
|
||||
);
|
||||
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 4, "
|
||||
$this->ExecuteMigrationWhenNeeded(4, "
|
||||
CREATE TABLE stock (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
product_id INTEGER NOT NULL,
|
||||
@ -50,7 +54,7 @@ class GrocyDbMigrator
|
||||
)"
|
||||
);
|
||||
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 5, "
|
||||
$this->ExecuteMigrationWhenNeeded(5, "
|
||||
CREATE TABLE stock_log (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
product_id INTEGER NOT NULL,
|
||||
@ -65,14 +69,14 @@ class GrocyDbMigrator
|
||||
)"
|
||||
);
|
||||
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 6, "
|
||||
$this->ExecuteMigrationWhenNeeded(6, "
|
||||
INSERT INTO locations (name, description) VALUES ('DefaultLocation', 'This is the first default location, edit or delete it');
|
||||
INSERT INTO quantity_units (name, description) VALUES ('DefaultQuantityUnit', 'This is the first default quantity unit, edit or delete it');
|
||||
INSERT INTO products (name, description, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('DefaultProduct1', 'This is the first default product, edit or delete it', 1, 1, 1, 1);
|
||||
INSERT INTO products (name, description, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('DefaultProduct2', 'This is the second default product, edit or delete it', 1, 1, 1, 1);"
|
||||
);
|
||||
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 7, "
|
||||
$this->ExecuteMigrationWhenNeeded(7, "
|
||||
CREATE VIEW stock_missing_products
|
||||
AS
|
||||
SELECT p.id, MAX(p.name) AS name, p.min_stock_amount - IFNULL(SUM(s.amount), 0) AS amount_missing
|
||||
@ -84,7 +88,7 @@ class GrocyDbMigrator
|
||||
HAVING IFNULL(SUM(s.amount), 0) < p.min_stock_amount;"
|
||||
);
|
||||
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 8, "
|
||||
$this->ExecuteMigrationWhenNeeded(8, "
|
||||
CREATE VIEW stock_current
|
||||
AS
|
||||
SELECT product_id, SUM(amount) AS amount, MIN(best_before_date) AS best_before_date
|
||||
@ -93,7 +97,7 @@ class GrocyDbMigrator
|
||||
ORDER BY MIN(best_before_date) ASC;"
|
||||
);
|
||||
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 9, "
|
||||
$this->ExecuteMigrationWhenNeeded(9, "
|
||||
CREATE TABLE shopping_list (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
product_id INTEGER NOT NULL UNIQUE,
|
||||
@ -103,7 +107,7 @@ class GrocyDbMigrator
|
||||
)"
|
||||
);
|
||||
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 10, "
|
||||
$this->ExecuteMigrationWhenNeeded(10, "
|
||||
CREATE TABLE habits (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
@ -114,7 +118,7 @@ class GrocyDbMigrator
|
||||
)"
|
||||
);
|
||||
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 11, "
|
||||
$this->ExecuteMigrationWhenNeeded(11, "
|
||||
CREATE TABLE habits_log (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
habit_id INTEGER NOT NULL,
|
||||
@ -123,7 +127,7 @@ class GrocyDbMigrator
|
||||
)"
|
||||
);
|
||||
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 12, "
|
||||
$this->ExecuteMigrationWhenNeeded(12, "
|
||||
CREATE VIEW habits_current
|
||||
AS
|
||||
SELECT habit_id, MAX(tracked_time) AS last_tracked_time
|
||||
@ -132,7 +136,7 @@ class GrocyDbMigrator
|
||||
ORDER BY MAX(tracked_time) DESC;"
|
||||
);
|
||||
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 13, "
|
||||
$this->ExecuteMigrationWhenNeeded(13, "
|
||||
CREATE TABLE batteries (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
@ -143,7 +147,7 @@ class GrocyDbMigrator
|
||||
)"
|
||||
);
|
||||
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 14, "
|
||||
$this->ExecuteMigrationWhenNeeded(14, "
|
||||
CREATE TABLE battery_charge_cycles (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
battery_id TEXT NOT NULL,
|
||||
@ -152,7 +156,7 @@ class GrocyDbMigrator
|
||||
)"
|
||||
);
|
||||
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 15, "
|
||||
$this->ExecuteMigrationWhenNeeded(15, "
|
||||
CREATE VIEW batteries_current
|
||||
AS
|
||||
SELECT battery_id, MAX(tracked_time) AS last_tracked_time
|
||||
@ -161,11 +165,11 @@ class GrocyDbMigrator
|
||||
ORDER BY MAX(tracked_time) DESC;"
|
||||
);
|
||||
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 16, "
|
||||
$this->ExecuteMigrationWhenNeeded(16, "
|
||||
ALTER TABLE shopping_list RENAME TO shopping_list_old;"
|
||||
);
|
||||
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 17, "
|
||||
$this->ExecuteMigrationWhenNeeded(17, "
|
||||
CREATE TABLE shopping_list (
|
||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||
product_id INTEGER,
|
||||
@ -176,25 +180,25 @@ class GrocyDbMigrator
|
||||
)"
|
||||
);
|
||||
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 18, "
|
||||
$this->ExecuteMigrationWhenNeeded(18, "
|
||||
INSERT INTO shopping_list
|
||||
(product_id, amount, amount_autoadded, row_created_timestamp)
|
||||
SELECT product_id, amount, amount_autoadded, row_created_timestamp
|
||||
FROM shopping_list_old"
|
||||
);
|
||||
|
||||
self::ExecuteMigrationWhenNeeded($pdo, 19, "
|
||||
$this->ExecuteMigrationWhenNeeded(19, "
|
||||
DROP TABLE shopping_list_old;"
|
||||
);
|
||||
}
|
||||
|
||||
private static function ExecuteMigrationWhenNeeded(PDO $pdo, int $migrationId, string $sql)
|
||||
private function ExecuteMigrationWhenNeeded(int $migrationId, string $sql)
|
||||
{
|
||||
$rowCount = DatabaseService::ExecuteDbQuery($pdo, 'SELECT COUNT(*) FROM migrations WHERE migration = ' . $migrationId)->fetchColumn();
|
||||
$rowCount = $this->DatabaseService->ExecuteDbQuery('SELECT COUNT(*) FROM migrations WHERE migration = ' . $migrationId)->fetchColumn();
|
||||
if (intval($rowCount) === 0)
|
||||
{
|
||||
DatabaseService::ExecuteDbStatement($pdo, $sql);
|
||||
DatabaseService::ExecuteDbStatement($pdo, 'INSERT INTO migrations (migration) VALUES (' . $migrationId . ')');
|
||||
$this->DatabaseService->ExecuteDbStatement($sql);
|
||||
$this->DatabaseService->ExecuteDbStatement('INSERT INTO migrations (migration) VALUES (' . $migrationId . ')');
|
||||
}
|
||||
}
|
||||
}
|
@ -1,64 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Services;
|
||||
|
||||
use Grocy\Services\ApplicationService;
|
||||
|
||||
class DatabaseService
|
||||
{
|
||||
private static $DbConnectionRaw;
|
||||
private $DbConnectionRaw;
|
||||
/**
|
||||
* @return PDO
|
||||
* @return \PDO
|
||||
*/
|
||||
public static function GetDbConnectionRaw($doMigrations = false)
|
||||
public function GetDbConnectionRaw()
|
||||
{
|
||||
if ($doMigrations === true)
|
||||
if ($this->DbConnectionRaw == null)
|
||||
{
|
||||
self::$DbConnectionRaw = null;
|
||||
$pdo = new \PDO('sqlite:' . __DIR__ . '/../data/grocy.db');
|
||||
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
||||
$this->DbConnectionRaw = $pdo;
|
||||
}
|
||||
|
||||
if (self::$DbConnectionRaw == null)
|
||||
{
|
||||
$pdo = new PDO('sqlite:' . __DIR__ . '/../data/grocy.db');
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
if ($doMigrations === true)
|
||||
{
|
||||
self::ExecuteDbStatement($pdo, "CREATE TABLE IF NOT EXISTS migrations (migration INTEGER NOT NULL PRIMARY KEY UNIQUE, execution_time_timestamp DATETIME DEFAULT (datetime('now', 'localtime')))");
|
||||
GrocyDbMigrator::MigrateDb($pdo);
|
||||
|
||||
if (ApplicationService::IsDemoInstallation())
|
||||
{
|
||||
GrocyDemoDataGenerator::PopulateDemoData($pdo);
|
||||
}
|
||||
return $this->DbConnectionRaw;
|
||||
}
|
||||
|
||||
self::$DbConnectionRaw = $pdo;
|
||||
}
|
||||
|
||||
return self::$DbConnectionRaw;
|
||||
}
|
||||
|
||||
private static $DbConnection;
|
||||
private $DbConnection;
|
||||
/**
|
||||
* @return LessQL\Database
|
||||
* @return \LessQL\Database
|
||||
*/
|
||||
public static function GetDbConnection($doMigrations = false)
|
||||
public function GetDbConnection()
|
||||
{
|
||||
if ($doMigrations === true)
|
||||
if ($this->DbConnection == null)
|
||||
{
|
||||
self::$DbConnection = null;
|
||||
$this->DbConnection = new \LessQL\Database($this->GetDbConnectionRaw());
|
||||
}
|
||||
|
||||
if (self::$DbConnection == null)
|
||||
{
|
||||
self::$DbConnection = new LessQL\Database(self::GetDbConnectionRaw($doMigrations));
|
||||
}
|
||||
|
||||
return self::$DbConnection;
|
||||
return $this->DbConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public static function ExecuteDbStatement(PDO $pdo, string $sql)
|
||||
public function ExecuteDbStatement(string $sql)
|
||||
{
|
||||
$pdo = $this->GetDbConnectionRaw();
|
||||
if ($pdo->exec($sql) === false)
|
||||
{
|
||||
throw new Exception($pdo->errorInfo());
|
||||
@ -68,11 +51,12 @@ class DatabaseService
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean|PDOStatement
|
||||
* @return boolean|\PDOStatement
|
||||
*/
|
||||
public static function ExecuteDbQuery(PDO $pdo, string $sql)
|
||||
public function ExecuteDbQuery(string $sql)
|
||||
{
|
||||
if (self::ExecuteDbStatement($pdo, $sql) === true)
|
||||
$pdo = $this->GetDbConnectionRaw();
|
||||
if ($this->ExecuteDbStatement($sql) === true)
|
||||
{
|
||||
return $pdo->query($sql);
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
<?php
|
||||
|
||||
class GrocyDemoDataGenerator
|
||||
namespace Grocy\Services;
|
||||
|
||||
class DemoDataGeneratorService extends BaseService
|
||||
{
|
||||
public static function PopulateDemoData(PDO $pdo)
|
||||
public function PopulateDemoData()
|
||||
{
|
||||
$rowCount = DatabaseService::ExecuteDbQuery($pdo, 'SELECT COUNT(*) FROM migrations WHERE migration = -1')->fetchColumn();
|
||||
$rowCount = $this->DatabaseService->ExecuteDbQuery('SELECT COUNT(*) FROM migrations WHERE migration = -1')->fetchColumn();
|
||||
if (intval($rowCount) === 0)
|
||||
{
|
||||
$sql = "
|
||||
@ -45,46 +47,47 @@ class GrocyDemoDataGenerator
|
||||
INSERT INTO migrations (migration) VALUES (-1);
|
||||
";
|
||||
|
||||
DatabaseService::ExecuteDbStatement($pdo, $sql);
|
||||
$this->DatabaseService->ExecuteDbStatement($sql);
|
||||
|
||||
StockService::AddProduct(3, 5, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
StockService::AddProduct(4, 5, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
StockService::AddProduct(5, 5, date('Y-m-d', strtotime('+20 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
StockService::AddProduct(6, 5, date('Y-m-d', strtotime('+600 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
StockService::AddProduct(7, 5, date('Y-m-d', strtotime('+800 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
StockService::AddProduct(8, 5, date('Y-m-d', strtotime('+900 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
StockService::AddProduct(9, 5, date('Y-m-d', strtotime('+14 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
StockService::AddProduct(10, 5, date('Y-m-d', strtotime('+21 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
StockService::AddProduct(11, 5, date('Y-m-d', strtotime('+10 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
StockService::AddProduct(12, 5, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
StockService::AddProduct(13, 5, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
StockService::AddProduct(14, 5, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
StockService::AddProduct(15, 5, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
StockService::AddMissingProductsToShoppingList();
|
||||
$stockService = new StockService();
|
||||
$stockService->AddProduct(3, 5, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
$stockService->AddProduct(4, 5, date('Y-m-d', strtotime('+180 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
$stockService->AddProduct(5, 5, date('Y-m-d', strtotime('+20 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
$stockService->AddProduct(6, 5, date('Y-m-d', strtotime('+600 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
$stockService->AddProduct(7, 5, date('Y-m-d', strtotime('+800 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
$stockService->AddProduct(8, 5, date('Y-m-d', strtotime('+900 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
$stockService->AddProduct(9, 5, date('Y-m-d', strtotime('+14 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
$stockService->AddProduct(10, 5, date('Y-m-d', strtotime('+21 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
$stockService->AddProduct(11, 5, date('Y-m-d', strtotime('+10 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
$stockService->AddProduct(12, 5, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
$stockService->AddProduct(13, 5, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
$stockService->AddProduct(14, 5, date('Y-m-d', strtotime('+2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
$stockService->AddProduct(15, 5, date('Y-m-d', strtotime('-2 days')), StockService::TRANSACTION_TYPE_PURCHASE);
|
||||
$stockService->AddMissingProductsToShoppingList();
|
||||
|
||||
HabitsService::TrackHabit(1, date('Y-m-d H:i:s', strtotime('-5 days')));
|
||||
HabitsService::TrackHabit(1, date('Y-m-d H:i:s', strtotime('-10 days')));
|
||||
HabitsService::TrackHabit(1, date('Y-m-d H:i:s', strtotime('-15 days')));
|
||||
HabitsService::TrackHabit(2, date('Y-m-d H:i:s', strtotime('-10 days')));
|
||||
HabitsService::TrackHabit(2, date('Y-m-d H:i:s', strtotime('-20 days')));
|
||||
$habitsService = new HabitsService();
|
||||
$habitsService->TrackHabit(1, date('Y-m-d H:i:s', strtotime('-5 days')));
|
||||
$habitsService->TrackHabit(1, date('Y-m-d H:i:s', strtotime('-10 days')));
|
||||
$habitsService->TrackHabit(1, date('Y-m-d H:i:s', strtotime('-15 days')));
|
||||
$habitsService->TrackHabit(2, date('Y-m-d H:i:s', strtotime('-10 days')));
|
||||
$habitsService->TrackHabit(2, date('Y-m-d H:i:s', strtotime('-20 days')));
|
||||
|
||||
BatteriesService::TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-200 days')));
|
||||
BatteriesService::TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-150 days')));
|
||||
BatteriesService::TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-100 days')));
|
||||
BatteriesService::TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-50 days')));
|
||||
BatteriesService::TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-200 days')));
|
||||
BatteriesService::TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-150 days')));
|
||||
BatteriesService::TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-100 days')));
|
||||
BatteriesService::TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-50 days')));
|
||||
BatteriesService::TrackChargeCycle(3, date('Y-m-d H:i:s', strtotime('-65 days')));
|
||||
$batteriesService = new BatteriesService();
|
||||
$batteriesService->TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-200 days')));
|
||||
$batteriesService->TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-150 days')));
|
||||
$batteriesService->TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-100 days')));
|
||||
$batteriesService->TrackChargeCycle(1, date('Y-m-d H:i:s', strtotime('-50 days')));
|
||||
$batteriesService->TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-200 days')));
|
||||
$batteriesService->TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-150 days')));
|
||||
$batteriesService->TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-100 days')));
|
||||
$batteriesService->TrackChargeCycle(2, date('Y-m-d H:i:s', strtotime('-50 days')));
|
||||
$batteriesService->TrackChargeCycle(3, date('Y-m-d H:i:s', strtotime('-65 days')));
|
||||
}
|
||||
}
|
||||
|
||||
public static function RecreateDemo()
|
||||
public function RecreateDemo()
|
||||
{
|
||||
unlink(__DIR__ . '/data/grocy.db');
|
||||
|
||||
$db = DatabaseService::GetDbConnectionRaw(true);
|
||||
self::PopulateDemoData($db);
|
||||
$this->PopulateDemoData($this->DatabaseService->GetDbConnectionRaw(true));
|
||||
}
|
||||
}
|
@ -1,22 +1,22 @@
|
||||
<?php
|
||||
|
||||
class HabitsService
|
||||
namespace Grocy\Services;
|
||||
|
||||
class HabitsService extends BaseService
|
||||
{
|
||||
const HABIT_TYPE_MANUALLY = 'manually';
|
||||
const HABIT_TYPE_DYNAMIC_REGULAR = 'dynamic-regular';
|
||||
|
||||
public static function GetCurrentHabits()
|
||||
public function GetCurrentHabits()
|
||||
{
|
||||
$sql = 'SELECT * from habits_current';
|
||||
return DatabaseService::ExecuteDbQuery(DatabaseService::GetDbConnectionRaw(), $sql)->fetchAll(PDO::FETCH_OBJ);
|
||||
return $this->DatabaseService->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
|
||||
}
|
||||
|
||||
public static function GetNextHabitTime(int $habitId)
|
||||
public function GetNextHabitTime(int $habitId)
|
||||
{
|
||||
$db = DatabaseService::GetDbConnection();
|
||||
|
||||
$habit = $db->habits($habitId);
|
||||
$habitLastLogRow = DatabaseService::ExecuteDbQuery(DatabaseService::GetDbConnectionRaw(), "SELECT * from habits_current WHERE habit_id = $habitId LIMIT 1")->fetch(PDO::FETCH_OBJ);
|
||||
$habit = $this->Database->habits($habitId);
|
||||
$habitLastLogRow = $this->DatabaseService->ExecuteDbQuery("SELECT * from habits_current WHERE habit_id = $habitId LIMIT 1")->fetch(\PDO::FETCH_OBJ);
|
||||
|
||||
switch ($habit->period_type)
|
||||
{
|
||||
@ -29,13 +29,11 @@ class HabitsService
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function GetHabitDetails(int $habitId)
|
||||
public function GetHabitDetails(int $habitId)
|
||||
{
|
||||
$db = DatabaseService::GetDbConnection();
|
||||
|
||||
$habit = $db->habits($habitId);
|
||||
$habitTrackedCount = $db->habits_log()->where('habit_id', $habitId)->count();
|
||||
$habitLastTrackedTime = $db->habits_log()->where('habit_id', $habitId)->max('tracked_time');
|
||||
$habit = $this->Database->habits($habitId);
|
||||
$habitTrackedCount = $this->Database->habits_log()->where('habit_id', $habitId)->count();
|
||||
$habitLastTrackedTime = $this->Database->habits_log()->where('habit_id', $habitId)->max('tracked_time');
|
||||
|
||||
return array(
|
||||
'habit' => $habit,
|
||||
@ -44,11 +42,9 @@ class HabitsService
|
||||
);
|
||||
}
|
||||
|
||||
public static function TrackHabit(int $habitId, string $trackedTime)
|
||||
public function TrackHabit(int $habitId, string $trackedTime)
|
||||
{
|
||||
$db = DatabaseService::GetDbConnection();
|
||||
|
||||
$logRow = $db->habits_log()->createRow(array(
|
||||
$logRow = $this->Database->habits_log()->createRow(array(
|
||||
'habit_id' => $habitId,
|
||||
'tracked_time' => $trackedTime
|
||||
));
|
||||
|
@ -1,11 +1,13 @@
|
||||
<?php
|
||||
|
||||
class SessionService
|
||||
namespace Grocy\Services;
|
||||
|
||||
class SessionService extends BaseService
|
||||
{
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public static function IsValidSession($sessionKey)
|
||||
public function IsValidSession($sessionKey)
|
||||
{
|
||||
if ($sessionKey === null || empty($sessionKey))
|
||||
{
|
||||
@ -20,7 +22,7 @@ class SessionService
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public static function CreateSession()
|
||||
public function CreateSession()
|
||||
{
|
||||
if (!file_exists(__DIR__ . '/../data/sessions'))
|
||||
{
|
||||
@ -28,7 +30,7 @@ class SessionService
|
||||
}
|
||||
|
||||
$now = time();
|
||||
foreach (new FilesystemIterator(__DIR__ . '/../data/sessions') as $file)
|
||||
foreach (new \FilesystemIterator(__DIR__ . '/../data/sessions') as $file)
|
||||
{
|
||||
if ($now - $file->getCTime() >= 2678400) //31 days
|
||||
{
|
||||
@ -41,7 +43,7 @@ class SessionService
|
||||
return $newSessionKey;
|
||||
}
|
||||
|
||||
public static function RemoveSession($sessionKey)
|
||||
public function RemoveSession($sessionKey)
|
||||
{
|
||||
unlink(__DIR__ . "/../data/sessions/$sessionKey.txt");
|
||||
}
|
||||
|
@ -1,33 +1,33 @@
|
||||
<?php
|
||||
|
||||
class StockService
|
||||
namespace Grocy\Services;
|
||||
|
||||
class StockService extends BaseService
|
||||
{
|
||||
const TRANSACTION_TYPE_PURCHASE = 'purchase';
|
||||
const TRANSACTION_TYPE_CONSUME = 'consume';
|
||||
const TRANSACTION_TYPE_INVENTORY_CORRECTION = 'inventory-correction';
|
||||
|
||||
public static function GetCurrentStock()
|
||||
public function GetCurrentStock()
|
||||
{
|
||||
$sql = 'SELECT * from stock_current';
|
||||
return DatabaseService::ExecuteDbQuery(DatabaseService::GetDbConnectionRaw(), $sql)->fetchAll(PDO::FETCH_OBJ);
|
||||
return $this->DatabaseService->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
|
||||
}
|
||||
|
||||
public static function GetMissingProducts()
|
||||
public function GetMissingProducts()
|
||||
{
|
||||
$sql = 'SELECT * from stock_missing_products';
|
||||
return DatabaseService::ExecuteDbQuery(DatabaseService::GetDbConnectionRaw(), $sql)->fetchAll(PDO::FETCH_OBJ);
|
||||
return $this->DatabaseService->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ);
|
||||
}
|
||||
|
||||
public static function GetProductDetails(int $productId)
|
||||
public function GetProductDetails(int $productId)
|
||||
{
|
||||
$db = DatabaseService::GetDbConnection();
|
||||
|
||||
$product = $db->products($productId);
|
||||
$productStockAmount = $db->stock()->where('product_id', $productId)->sum('amount');
|
||||
$productLastPurchased = $db->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_PURCHASE)->max('purchased_date');
|
||||
$productLastUsed = $db->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_CONSUME)->max('used_date');
|
||||
$quPurchase = $db->quantity_units($product->qu_id_purchase);
|
||||
$quStock = $db->quantity_units($product->qu_id_stock);
|
||||
$product = $this->Database->products($productId);
|
||||
$productStockAmount = $this->Database->stock()->where('product_id', $productId)->sum('amount');
|
||||
$productLastPurchased = $this->Database->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_PURCHASE)->max('purchased_date');
|
||||
$productLastUsed = $this->Database->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_CONSUME)->max('used_date');
|
||||
$quPurchase = $this->Database->quantity_units($product->qu_id_purchase);
|
||||
$quStock = $this->Database->quantity_units($product->qu_id_stock);
|
||||
|
||||
return array(
|
||||
'product' => $product,
|
||||
@ -39,14 +39,13 @@ class StockService
|
||||
);
|
||||
}
|
||||
|
||||
public static function AddProduct(int $productId, int $amount, string $bestBeforeDate, $transactionType)
|
||||
public function AddProduct(int $productId, int $amount, string $bestBeforeDate, $transactionType)
|
||||
{
|
||||
if ($transactionType === self::TRANSACTION_TYPE_CONSUME || $transactionType === self::TRANSACTION_TYPE_PURCHASE || $transactionType === self::TRANSACTION_TYPE_INVENTORY_CORRECTION)
|
||||
{
|
||||
$db = DatabaseService::GetDbConnection();
|
||||
$stockId = uniqid();
|
||||
|
||||
$logRow = $db->stock_log()->createRow(array(
|
||||
$logRow = $this->Database->stock_log()->createRow(array(
|
||||
'product_id' => $productId,
|
||||
'amount' => $amount,
|
||||
'best_before_date' => $bestBeforeDate,
|
||||
@ -56,7 +55,7 @@ class StockService
|
||||
));
|
||||
$logRow->save();
|
||||
|
||||
$stockRow = $db->stock()->createRow(array(
|
||||
$stockRow = $this->Database->stock()->createRow(array(
|
||||
'product_id' => $productId,
|
||||
'amount' => $amount,
|
||||
'best_before_date' => $bestBeforeDate,
|
||||
@ -73,14 +72,12 @@ class StockService
|
||||
}
|
||||
}
|
||||
|
||||
public static function ConsumeProduct(int $productId, int $amount, bool $spoiled, $transactionType)
|
||||
public function ConsumeProduct(int $productId, int $amount, bool $spoiled, $transactionType)
|
||||
{
|
||||
if ($transactionType === self::TRANSACTION_TYPE_CONSUME || $transactionType === self::TRANSACTION_TYPE_PURCHASE || $transactionType === self::TRANSACTION_TYPE_INVENTORY_CORRECTION)
|
||||
{
|
||||
$db = DatabaseService::GetDbConnection();
|
||||
|
||||
$productStockAmount = $db->stock()->where('product_id', $productId)->sum('amount');
|
||||
$potentialStockEntries = $db->stock()->where('product_id', $productId)->orderBy('best_before_date', 'ASC')->orderBy('purchased_date', 'ASC')->fetchAll(); //First expiring first, then first in first out
|
||||
$productStockAmount = $this->Database->stock()->where('product_id', $productId)->sum('amount');
|
||||
$potentialStockEntries = $this->Database->stock()->where('product_id', $productId)->orderBy('best_before_date', 'ASC')->orderBy('purchased_date', 'ASC')->fetchAll(); //First expiring first, then first in first out
|
||||
|
||||
if ($amount > $productStockAmount)
|
||||
{
|
||||
@ -96,7 +93,7 @@ class StockService
|
||||
|
||||
if ($amount >= $stockEntry->amount) //Take the whole stock entry
|
||||
{
|
||||
$logRow = $db->stock_log()->createRow(array(
|
||||
$logRow = $this->Database->stock_log()->createRow(array(
|
||||
'product_id' => $stockEntry->product_id,
|
||||
'amount' => $stockEntry->amount * -1,
|
||||
'best_before_date' => $stockEntry->best_before_date,
|
||||
@ -113,7 +110,7 @@ class StockService
|
||||
}
|
||||
else //Stock entry amount is > than needed amount -> split the stock entry resp. update the amount
|
||||
{
|
||||
$logRow = $db->stock_log()->createRow(array(
|
||||
$logRow = $this->Database->stock_log()->createRow(array(
|
||||
'product_id' => $stockEntry->product_id,
|
||||
'amount' => $amount * -1,
|
||||
'best_before_date' => $stockEntry->best_before_date,
|
||||
@ -142,36 +139,33 @@ class StockService
|
||||
}
|
||||
}
|
||||
|
||||
public static function InventoryProduct(int $productId, int $newAmount, string $bestBeforeDate)
|
||||
public function InventoryProduct(int $productId, int $newAmount, string $bestBeforeDate)
|
||||
{
|
||||
$db = DatabaseService::GetDbConnection();
|
||||
$productStockAmount = $db->stock()->where('product_id', $productId)->sum('amount');
|
||||
$productStockAmount = $this->Database->stock()->where('product_id', $productId)->sum('amount');
|
||||
|
||||
if ($newAmount > $productStockAmount)
|
||||
{
|
||||
$amountToAdd = $newAmount - $productStockAmount;
|
||||
self::AddProduct($productId, $amountToAdd, $bestBeforeDate, self::TRANSACTION_TYPE_INVENTORY_CORRECTION);
|
||||
$this->AddProduct($productId, $amountToAdd, $bestBeforeDate, self::TRANSACTION_TYPE_INVENTORY_CORRECTION);
|
||||
}
|
||||
else if ($newAmount < $productStockAmount)
|
||||
{
|
||||
$amountToRemove = $productStockAmount - $newAmount;
|
||||
self::ConsumeProduct($productId, $amountToRemove, false, self::TRANSACTION_TYPE_INVENTORY_CORRECTION);
|
||||
$this->ConsumeProduct($productId, $amountToRemove, false, self::TRANSACTION_TYPE_INVENTORY_CORRECTION);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function AddMissingProductsToShoppingList()
|
||||
public function AddMissingProductsToShoppingList()
|
||||
{
|
||||
$db = DatabaseService::GetDbConnection();
|
||||
|
||||
$missingProducts = self::GetMissingProducts();
|
||||
$missingProducts = $this->GetMissingProducts();
|
||||
foreach ($missingProducts as $missingProduct)
|
||||
{
|
||||
$product = $db->products()->where('id', $missingProduct->id)->fetch();
|
||||
$product = $this->Database->products()->where('id', $missingProduct->id)->fetch();
|
||||
$amount = ceil($missingProduct->amount_missing / $product->qu_factor_purchase_to_stock);
|
||||
|
||||
$alreadyExistingEntry = $db->shopping_list()->where('product_id', $missingProduct->id)->fetch();
|
||||
$alreadyExistingEntry = $this->Database->shopping_list()->where('product_id', $missingProduct->id)->fetch();
|
||||
if ($alreadyExistingEntry) //Update
|
||||
{
|
||||
$alreadyExistingEntry->update(array(
|
||||
@ -180,7 +174,7 @@ class StockService
|
||||
}
|
||||
else //Insert
|
||||
{
|
||||
$shoppinglistRow = $db->shopping_list()->createRow(array(
|
||||
$shoppinglistRow = $this->Database->shopping_list()->createRow(array(
|
||||
'product_id' => $missingProduct->id,
|
||||
'amount_autoadded' => $amount
|
||||
));
|
||||
|
@ -1,3 +1,6 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header">
|
||||
@ -44,3 +47,4 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@stop
|
@ -1,3 +1,11 @@
|
||||
<?php
|
||||
use Grocy\Services\BatteriesService;
|
||||
$batteriesService = new BatteriesService();
|
||||
?>
|
||||
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header">Batteries overview</h1>
|
||||
@ -13,18 +21,18 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($current as $curentBatteryEntry) : ?>
|
||||
<tr class="<?php if (GrocyPhpHelper::FindObjectInArrayByPropertyValue($batteries, 'id', $curentBatteryEntry->battery_id)->charge_interval_days > 0 && BatteriesService::GetNextChargeTime($curentBatteryEntry->battery_id) < date('Y-m-d H:i:s')) echo 'error-bg'; ?>">
|
||||
<tr class="<?php if (FindObjectInArrayByPropertyValue($batteries, 'id', $curentBatteryEntry->battery_id)->charge_interval_days > 0 && $batteriesService->GetNextChargeTime($curentBatteryEntry->battery_id) < date('Y-m-d H:i:s')) echo 'error-bg'; ?>">
|
||||
<td>
|
||||
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($batteries, 'id', $curentBatteryEntry->battery_id)->name; ?>
|
||||
<?php echo FindObjectInArrayByPropertyValue($batteries, 'id', $curentBatteryEntry->battery_id)->name; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo $curentBatteryEntry->last_tracked_time; ?>
|
||||
<time class="timeago timeago-contextual" datetime="<?php echo $curentBatteryEntry->last_tracked_time; ?>"></time>
|
||||
</td>
|
||||
<td>
|
||||
<?php if (GrocyPhpHelper::FindObjectInArrayByPropertyValue($batteries, 'id', $curentBatteryEntry->battery_id)->charge_interval_days > 0): ?>
|
||||
<?php echo BatteriesService::GetNextChargeTime($curentBatteryEntry->battery_id); ?>
|
||||
<time class="timeago timeago-contextual" datetime="<?php echo BatteriesService::GetNextChargeTime($curentBatteryEntry->battery_id); ?>"></time>
|
||||
<?php if (FindObjectInArrayByPropertyValue($batteries, 'id', $curentBatteryEntry->battery_id)->charge_interval_days > 0): ?>
|
||||
<?php echo $batteriesService->GetNextChargeTime($curentBatteryEntry->battery_id); ?>
|
||||
<time class="timeago timeago-contextual" datetime="<?php echo $batteriesService->GetNextChargeTime($curentBatteryEntry->battery_id); ?>"></time>
|
||||
<?php else: ?>
|
||||
...
|
||||
<?php endif; ?>
|
||||
@ -36,3 +44,4 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@stop
|
@ -1,3 +1,6 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header"><?php echo $title; ?></h1>
|
||||
@ -31,3 +34,4 @@
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@stop
|
@ -1,3 +1,6 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header">Battery tracking</h1>
|
||||
@ -40,3 +43,4 @@
|
||||
<strong>Last charged:</strong> <span id="selected-battery-last-charged"></span> <time id="selected-battery-last-charged-timeago" class="timeago timeago-contextual"></time><br>
|
||||
</p>
|
||||
</div>
|
||||
@stop
|
@ -1,3 +1,6 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header">Consume</h1>
|
||||
@ -43,3 +46,4 @@
|
||||
<strong>Last used:</strong> <span id="selected-product-last-used"></span> <time id="selected-product-last-used-timeago" class="timeago timeago-contextual"></time>
|
||||
</p>
|
||||
</div>
|
||||
@stop
|
@ -1,3 +1,6 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header"><?php echo $title; ?></h1>
|
||||
@ -44,3 +47,4 @@
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@stop
|
@ -1,3 +1,6 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header">
|
||||
@ -48,3 +51,4 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@stop
|
@ -1,3 +1,11 @@
|
||||
<?php
|
||||
use Grocy\Services\HabitsService;
|
||||
$habitsService = new HabitsService();
|
||||
?>
|
||||
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header">Habits overview</h1>
|
||||
@ -13,14 +21,14 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($currentHabits as $curentHabitEntry) : ?>
|
||||
<tr class="<?php if (GrocyPhpHelper::FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->period_type === HabitsService::HABIT_TYPE_DYNAMIC_REGULAR && HabitsService::GetNextHabitTime($curentHabitEntry->habit_id) < date('Y-m-d H:i:s')) echo 'error-bg'; ?>">
|
||||
<tr class="<?php if (FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->period_type === HabitsService::HABIT_TYPE_DYNAMIC_REGULAR && $habitsService->GetNextHabitTime($curentHabitEntry->habit_id) < date('Y-m-d H:i:s')) echo 'error-bg'; ?>">
|
||||
<td>
|
||||
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->name; ?>
|
||||
<?php echo FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->name; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if (GrocyPhpHelper::FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->period_type === HabitsService::HABIT_TYPE_DYNAMIC_REGULAR): ?>
|
||||
<?php echo HabitsService::GetNextHabitTime($curentHabitEntry->habit_id); ?>
|
||||
<time class="timeago timeago-contextual" datetime="<?php echo HabitsService::GetNextHabitTime($curentHabitEntry->habit_id); ?>"></time>
|
||||
<?php if (FindObjectInArrayByPropertyValue($habits, 'id', $curentHabitEntry->habit_id)->period_type === HabitsService::HABIT_TYPE_DYNAMIC_REGULAR): ?>
|
||||
<?php echo $habitsService->GetNextHabitTime($curentHabitEntry->habit_id); ?>
|
||||
<time class="timeago timeago-contextual" datetime="<?php echo $habitsService->GetNextHabitTime($curentHabitEntry->habit_id); ?>"></time>
|
||||
<?php else: ?>
|
||||
...
|
||||
<?php endif; ?>
|
||||
@ -36,3 +44,4 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@stop
|
@ -1,3 +1,6 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header">Habit tracking</h1>
|
||||
@ -40,3 +43,4 @@
|
||||
<strong>Last tracked:</strong> <span id="selected-habit-last-tracked"></span> <time id="selected-habit-last-tracked-timeago" class="timeago timeago-contextual"></time><br>
|
||||
</p>
|
||||
</div>
|
||||
@stop
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
@ -1,3 +1,6 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-4 col-sm-offset-3 col-md-3 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header">Inventory</h1>
|
||||
@ -50,3 +53,4 @@
|
||||
<strong>Last used:</strong> <span id="selected-product-last-used"></span> <time id="selected-product-last-used-timeago" class="timeago timeago-contextual"></time>
|
||||
</p>
|
||||
</div>
|
||||
@stop
|
@ -1,3 +1,10 @@
|
||||
<?php
|
||||
|
||||
use Grocy\Services\ApplicationService;
|
||||
$applicationService = new ApplicationService();
|
||||
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
@ -9,24 +16,24 @@
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
|
||||
<meta name="author" content="Bernd Bestel (bernd@berrnd.de)">
|
||||
<link rel="icon" type="image/png" sizes="200x200" href="/grocy.png">
|
||||
<link rel="icon" type="image/png" sizes="200x200" href="/views/img/grocy.png">
|
||||
|
||||
<title><?php echo $title; ?> | grocy</title>
|
||||
|
||||
<link href="/bower_components/bootstrap/dist/css/bootstrap.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/bower_components/font-awesome/css/font-awesome.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/bower_components/bootstrap-datepicker/dist/css/bootstrap-datepicker3.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/bower_components/bootstrap-combobox/css/bootstrap-combobox.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/bower_components/datatables.net-responsive-bs/css/responsive.bootstrap.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/bower_components/toastr/toastr.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/bower_components/tagmanager/tagmanager.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/bower_components/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/vendor_unmanaged/noto-sans-v6-latin/noto-sans-v6-latin.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/style.css?v=<?php echo ApplicationService::GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/bower_components/bootstrap/dist/css/bootstrap.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/bower_components/font-awesome/css/font-awesome.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/bower_components/bootstrap-datepicker/dist/css/bootstrap-datepicker3.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/bower_components/bootstrap-combobox/css/bootstrap-combobox.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/bower_components/datatables.net-responsive-bs/css/responsive.bootstrap.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/bower_components/toastr/toastr.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/bower_components/tagmanager/tagmanager.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/bower_components/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/vendor_unmanaged/noto-sans-v6-latin/noto-sans-v6-latin.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
<link href="/views/css/grocy.css?v=<?php echo $applicationService->GetInstalledVersion(); ?>" rel="stylesheet">
|
||||
|
||||
<script src="/bower_components/jquery/dist/jquery.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
|
||||
<script src="/grocy.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/jquery/dist/jquery.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
|
||||
<script src="/views/js/grocy.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@ -116,7 +123,7 @@
|
||||
<br>
|
||||
Created with passion since 2017
|
||||
<br>
|
||||
Version <?php echo ApplicationService::GetInstalledVersion(); ?>
|
||||
Version <?php echo $applicationService->GetInstalledVersion(); ?>
|
||||
<br>
|
||||
Life runs on code
|
||||
<br>
|
||||
@ -193,7 +200,7 @@
|
||||
<br>
|
||||
Created with passion since 2017
|
||||
<br>
|
||||
Version <?php echo ApplicationService::GetInstalledVersion(); ?>
|
||||
Version <?php echo $applicationService->GetInstalledVersion(); ?>
|
||||
<br>
|
||||
Life runs on code
|
||||
<br>
|
||||
@ -204,30 +211,31 @@
|
||||
|
||||
</div>
|
||||
|
||||
<script>Grocy.ContentPage = '<?php echo $contentPage; ?>';</script>
|
||||
<?php include __DIR__ . '/../' . $contentPage; ?>
|
||||
<script>Grocy.ContentPage = '{{ $contentPage }}';</script>
|
||||
@section('content')
|
||||
@show
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/bower_components/bootstrap/dist/js/bootstrap.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/bootbox/bootbox.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/jquery.serializeJSON/jquery.serializejson.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/moment/min/moment.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/bootstrap-validator/dist/validator.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/bootstrap-combobox/js/bootstrap-combobox.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/datatables.net/js/jquery.dataTables.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/datatables.net-responsive/js/dataTables.responsive.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/datatables.net-responsive-bs/js/responsive.bootstrap.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/jquery-timeago/jquery.timeago.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/toastr/toastr.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/tagmanager/tagmanager.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js?v=<?php echo ApplicationService::GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/bootstrap/dist/js/bootstrap.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/bootbox/bootbox.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/jquery.serializeJSON/jquery.serializejson.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/bootstrap-datepicker/dist/js/bootstrap-datepicker.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/moment/min/moment.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/bootstrap-validator/dist/validator.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/bootstrap-combobox/js/bootstrap-combobox.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/datatables.net/js/jquery.dataTables.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/datatables.net-responsive/js/dataTables.responsive.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/datatables.net-responsive-bs/js/responsive.bootstrap.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/jquery-timeago/jquery.timeago.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/toastr/toastr.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/tagmanager/tagmanager.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
|
||||
<script src="/bower_components/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js?v=<?php echo $applicationService->GetInstalledVersion(); ?>"></script>
|
||||
|
||||
<?php if (file_exists(__DIR__ . '/' . str_replace('.php', '.js', $contentPage))) : ?>
|
||||
<script src="/views/<?php echo str_replace('.php', '.js', $contentPage) . '?v=' . ApplicationService::GetInstalledVersion(); ?>"></script>
|
||||
<?php if (file_exists(__DIR__ . '/../../views/viewjs/' . str_replace('.php', '.js', $contentPage))) : ?>
|
||||
<script src="/views/viewjs/<?php echo str_replace('.php', '.js', $contentPage) . '?v=' . $applicationService->GetInstalledVersion(); ?>"></script>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (file_exists(__DIR__ . '/../data/add_before_end_body.html')) include __DIR__ . '/../data/add_before_end_body.html' ?>
|
@ -1,3 +1,6 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header"><?php echo $title; ?></h1>
|
||||
@ -26,3 +29,4 @@
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@stop
|
@ -1,3 +1,6 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header">
|
||||
@ -40,3 +43,4 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@stop
|
@ -1,3 +1,6 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-md-4 col-md-offset-5 main">
|
||||
|
||||
<h1 class="page-header text-center">Login</h1>
|
||||
@ -21,3 +24,4 @@
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@stop
|
@ -1,3 +1,6 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header"><?php echo $title; ?></h1>
|
||||
@ -81,3 +84,4 @@
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@stop
|
@ -1,3 +1,6 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header">
|
||||
@ -36,16 +39,16 @@
|
||||
<?php echo $product->name; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($locations, 'id', $product->location_id)->name; ?>
|
||||
<?php echo FindObjectInArrayByPropertyValue($locations, 'id', $product->location_id)->name; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo $product->min_stock_amount; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($quantityunits, 'id', $product->qu_id_purchase)->name; ?>
|
||||
<?php echo FindObjectInArrayByPropertyValue($quantityunits, 'id', $product->qu_id_purchase)->name; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($quantityunits, 'id', $product->qu_id_stock)->name; ?>
|
||||
<?php echo FindObjectInArrayByPropertyValue($quantityunits, 'id', $product->qu_id_stock)->name; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo $product->qu_factor_purchase_to_stock; ?>
|
||||
@ -60,3 +63,4 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@stop
|
@ -1,3 +1,6 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-4 col-sm-offset-3 col-md-3 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header">Purchase</h1>
|
||||
@ -49,3 +52,4 @@
|
||||
<strong>Last used:</strong> <span id="selected-product-last-used"></span> <time id="selected-product-last-used-timeago" class="timeago timeago-contextual"></time>
|
||||
</p>
|
||||
</div>
|
||||
@stop
|
@ -1,3 +1,6 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-3 col-sm-offset-3 col-md-4 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header"><?php echo $title; ?></h1>
|
||||
@ -26,3 +29,4 @@
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@stop
|
@ -1,3 +1,6 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header">
|
||||
@ -40,3 +43,4 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@stop
|
@ -1,3 +1,6 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header">
|
||||
@ -31,10 +34,10 @@
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<?php if (!empty($listItem->product_id)) echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id)->name . '<br>'; ?><em><?php echo $listItem->note; ?></em>
|
||||
<?php if (!empty($listItem->product_id)) echo FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id)->name . '<br>'; ?><em><?php echo $listItem->note; ?></em>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo $listItem->amount + $listItem->amount_autoadded; if (!empty($listItem->product_id)) echo ' ' . GrocyPhpHelper::FindObjectInArrayByPropertyValue($quantityunits, 'id', GrocyPhpHelper::FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id)->qu_id_purchase)->name; ?>
|
||||
<?php echo $listItem->amount + $listItem->amount_autoadded; if (!empty($listItem->product_id)) echo ' ' . FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $listItem->product_id)->qu_id_purchase)->name; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
@ -43,3 +46,4 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@stop
|
@ -1,3 +1,6 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-3 col-sm-offset-3 col-md-3 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header"><?php echo $title; ?></h1>
|
||||
@ -48,3 +51,4 @@
|
||||
<strong>Last used:</strong> <span id="selected-product-last-used"></span> <time id="selected-product-last-used-timeago" class="timeago timeago-contextual"></time>
|
||||
</p>
|
||||
</div>
|
||||
@stop
|
@ -1,11 +1,14 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('content')
|
||||
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
|
||||
|
||||
<h1 class="page-header">Stock overview <span class="text-muded small"><strong><?php echo count($currentStock) ?></strong> products with <strong><?php echo GrocyPhpHelper::SumArrayValue($currentStock, 'amount'); ?></strong> units in stock</span></h1>
|
||||
<h1 class="page-header">Stock overview <span class="text-muded small"><strong><?php echo count($currentStock) ?></strong> products with <strong><?php echo SumArrayValue($currentStock, 'amount'); ?></strong> units in stock</span></h1>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<p class="btn btn-lg btn-warning no-real-button"><strong><?php echo count(GrocyPhpHelper::FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime('+5 days')), '<')); ?></strong> products expiring within the next 5 days</p>
|
||||
<p class="btn btn-lg btn-danger no-real-button"><strong><?php echo count(GrocyPhpHelper::FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime('-1 days')), '<')); ?></strong> products are already expired</p>
|
||||
<p class="btn btn-lg btn-warning no-real-button"><strong><?php echo count(FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime('+5 days')), '<')); ?></strong> products expiring within the next 5 days</p>
|
||||
<p class="btn btn-lg btn-danger no-real-button"><strong><?php echo count(FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime('-1 days')), '<')); ?></strong> products are already expired</p>
|
||||
<p class="btn btn-lg btn-info no-real-button"><strong><?php echo count($missingProducts); ?></strong> products are below defined min. stock amount</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -23,12 +26,12 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($currentStock as $currentStockEntry) : ?>
|
||||
<tr class="<?php if ($currentStockEntry->best_before_date < date('Y-m-d', strtotime('-1 days'))) echo 'error-bg'; else if ($currentStockEntry->best_before_date < date('Y-m-d', strtotime('+5 days'))) echo 'warning-bg'; else if (GrocyPhpHelper::FindObjectInArrayByPropertyValue($missingProducts, 'id', $currentStockEntry->product_id) !== null) echo 'info-bg'; ?>">
|
||||
<tr class="<?php if ($currentStockEntry->best_before_date < date('Y-m-d', strtotime('-1 days'))) echo 'error-bg'; else if ($currentStockEntry->best_before_date < date('Y-m-d', strtotime('+5 days'))) echo 'warning-bg'; else if (FindObjectInArrayByPropertyValue($missingProducts, 'id', $currentStockEntry->product_id) !== null) echo 'info-bg'; ?>">
|
||||
<td>
|
||||
<?php echo GrocyPhpHelper::FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name; ?>
|
||||
<?php echo FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo $currentStockEntry->amount . ' ' . GrocyPhpHelper::FindObjectInArrayByPropertyValue($quantityunits, 'id', GrocyPhpHelper::FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name; ?>
|
||||
<?php echo $currentStockEntry->amount . ' ' . FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo $currentStockEntry->best_before_date; ?>
|
||||
@ -41,3 +44,4 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@stop
|
@ -7,7 +7,7 @@
|
||||
Grocy.FetchJson('/api/habits/get-habit-details/' + jsonForm.habit_id,
|
||||
function (habitDetails)
|
||||
{
|
||||
Grocy.FetchJson('/api/habits/track-habit/' + jsonForm.habit_id + '?tracked_time=' + $('#tracked_time').val(),
|
||||
Grocy.FetchJson('/api/habits/track-habit-exeuction/' + jsonForm.habit_id + '?tracked_time=' + $('#tracked_time').val(),
|
||||
function(result)
|
||||
{
|
||||
toastr.success('Tracked execution of habit ' + habitDetails.habit.name + ' on ' + $('#tracked_time').val());
|
||||
|
Loading…
x
Reference in New Issue
Block a user