From fe83e2fa6f70dc72b1bcc56dd7470c0764c944a6 Mon Sep 17 00:00:00 2001 From: Bernd Bestel Date: Sat, 27 Oct 2018 10:55:30 +0200 Subject: [PATCH] Created API endpoints to undo battery charge cycles and chore executions (references #63) --- controllers/BatteriesApiController.php | 13 ++++ controllers/ChoresApiController.php | 13 ++++ controllers/ChoresController.php | 2 +- grocy.openapi.json | 82 ++++++++++++++++++++++++++ migrations/0044.sql | 18 ++++++ routes.php | 2 + services/BatteriesService.php | 19 +++++- services/ChoresService.php | 21 ++++++- 8 files changed, 164 insertions(+), 6 deletions(-) diff --git a/controllers/BatteriesApiController.php b/controllers/BatteriesApiController.php index 82bf3ce4..dfc131d8 100644 --- a/controllers/BatteriesApiController.php +++ b/controllers/BatteriesApiController.php @@ -49,4 +49,17 @@ class BatteriesApiController extends BaseApiController { return $this->ApiResponse($this->BatteriesService->GetCurrent()); } + + public function UndoChargeCycle(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args) + { + try + { + $this->ApiResponse($this->BatteriesService->UndoChargeCycle($args['chargeCycleId'])); + return $this->ApiResponse(array('success' => true)); + } + catch (\Exception $ex) + { + return $this->VoidApiActionResponse($response, false, 400, $ex->getMessage()); + } + } } diff --git a/controllers/ChoresApiController.php b/controllers/ChoresApiController.php index ab1a2103..41886140 100644 --- a/controllers/ChoresApiController.php +++ b/controllers/ChoresApiController.php @@ -55,4 +55,17 @@ class ChoresApiController extends BaseApiController { return $this->ApiResponse($this->ChoresService->GetCurrent()); } + + public function UndoChoreExecution(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args) + { + try + { + $this->ApiResponse($this->ChoresService->UndoChoreExecution($args['executionId'])); + return $this->ApiResponse(array('success' => true)); + } + catch (\Exception $ex) + { + return $this->VoidApiActionResponse($response, false, 400, $ex->getMessage()); + } + } } diff --git a/controllers/ChoresController.php b/controllers/ChoresController.php index a52ca74c..09d916fd 100644 --- a/controllers/ChoresController.php +++ b/controllers/ChoresController.php @@ -41,7 +41,7 @@ class ChoresController extends BaseController public function Analysis(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args) { return $this->AppContainer->view->render($response, 'choresanalysis', [ - 'choresLog' => $this->Database->chores_log()->orderBy('tracked_time', 'DESC'), + 'choresLog' => $this->Database->chores_log()->where('undone', 0)->orderBy('tracked_time', 'DESC'), 'chores' => $this->Database->chores()->orderBy('name'), 'users' => $this->Database->users()->orderBy('username') ]); diff --git a/grocy.openapi.json b/grocy.openapi.json index cce2e53a..35fbd957 100644 --- a/grocy.openapi.json +++ b/grocy.openapi.json @@ -1514,6 +1514,47 @@ } } }, + "/chores/undo-chore-execution/{executionId}": { + "get": { + "description": "Undoes a chore execution", + "tags": [ + "Chores" + ], + "parameters": [ + { + "in": "path", + "name": "executionId", + "required": true, + "description": "A valid chore execution id", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "A VoidApiActionResponse object", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidApiActionResponse" + } + } + } + }, + "400": { + "description": "A VoidApiActionResponse object (possible errors are: Not existing booking)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorExampleVoidApiActionResponse" + } + } + } + } + } + } + }, "/batteries/track-charge-cycle/{batteryId}": { "get": { "description": "Tracks a charge cycle of the given battery", @@ -1629,6 +1670,47 @@ } } }, + "/batteries/undo-charge-cycle/{chargeCycleId}": { + "get": { + "description": "Undoes a chore execution", + "tags": [ + "Batteries" + ], + "parameters": [ + { + "in": "path", + "name": "chargeCycleId", + "required": true, + "description": "A valid charge cycle id", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "A VoidApiActionResponse object", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VoidApiActionResponse" + } + } + } + }, + "400": { + "description": "A VoidApiActionResponse object (possible errors are: Not existing booking)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorExampleVoidApiActionResponse" + } + } + } + } + } + } + }, "/tasks/get-current": { "get": { "description": "Returns all tasks which are not done yet", diff --git a/migrations/0044.sql b/migrations/0044.sql index 0657fb4f..41c68b6e 100644 --- a/migrations/0044.sql +++ b/migrations/0044.sql @@ -6,3 +6,21 @@ SET undone = 0; ALTER TABLE stock_log ADD undone_timestamp DATETIME; + +ALTER TABLE chores_log +ADD undone TINYINT NOT NULL DEFAULT 0 CHECK(undone IN (0, 1)); + +UPDATE chores_log +SET undone = 0; + +ALTER TABLE chores_log +ADD undone_timestamp DATETIME; + +ALTER TABLE battery_charge_cycles +ADD undone TINYINT NOT NULL DEFAULT 0 CHECK(undone IN (0, 1)); + +UPDATE battery_charge_cycles +SET undone = 0; + +ALTER TABLE battery_charge_cycles +ADD undone_timestamp DATETIME; diff --git a/routes.php b/routes.php index d11a497b..2d5ad2ec 100644 --- a/routes.php +++ b/routes.php @@ -124,11 +124,13 @@ $app->group('/api', function() $this->get('/chores/track-chore-execution/{choreId}', '\Grocy\Controllers\ChoresApiController:TrackChoreExecution'); $this->get('/chores/get-chore-details/{choreId}', '\Grocy\Controllers\ChoresApiController:ChoreDetails'); $this->get('/chores/get-current', '\Grocy\Controllers\ChoresApiController:Current'); + $this->get('/chores/undo-chore-execution/{executionId}', '\Grocy\Controllers\ChoresApiController:UndoChoreExecution'); // Batteries $this->get('/batteries/track-charge-cycle/{batteryId}', '\Grocy\Controllers\BatteriesApiController:TrackChargeCycle'); $this->get('/batteries/get-battery-details/{batteryId}', '\Grocy\Controllers\BatteriesApiController:BatteryDetails'); $this->get('/batteries/get-current', '\Grocy\Controllers\BatteriesApiController:Current'); + $this->get('/batteries/undo-charge-cycle/{chargeCycleId}', '\Grocy\Controllers\BatteriesApiController:UndoChargeCycle'); // Tasks $this->get('/tasks/get-current', '\Grocy\Controllers\TasksApiController:Current'); diff --git a/services/BatteriesService.php b/services/BatteriesService.php index 5075b8e5..5e1de622 100644 --- a/services/BatteriesService.php +++ b/services/BatteriesService.php @@ -18,8 +18,8 @@ class BatteriesService extends BaseService } $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'); + $batteryChargeCylcesCount = $this->Database->battery_charge_cycles()->where('battery_id = :1 AND undone = 0', $batteryId)->count(); + $batteryLastChargedTime = $this->Database->battery_charge_cycles()->where('battery_id = :1 AND undone = 0', $batteryId)->max('tracked_time'); $nextChargeTime = $this->Database->batteries_current()->where('battery_id', $batteryId)->min('next_estimated_charge_time'); return array( @@ -51,4 +51,19 @@ class BatteriesService extends BaseService $batteryRow = $this->Database->batteries()->where('id = :1', $batteryId)->fetch(); return $batteryRow !== null; } + + public function UndoChargeCycle($chargeCycleId) + { + $logRow = $this->Database->battery_charge_cycles()->where('id = :1 AND undone = 0', $chargeCycleId)->fetch(); + if ($logRow == null) + { + throw new \Exception('Charge cycle does not exist or was already undone'); + } + + // Update log entry + $logRow->update(array( + 'undone' => 1, + 'undone_timestamp' => date('Y-m-d H:i:s') + )); + } } diff --git a/services/ChoresService.php b/services/ChoresService.php index 66b3ec97..e84d9319 100644 --- a/services/ChoresService.php +++ b/services/ChoresService.php @@ -21,11 +21,11 @@ class ChoresService extends BaseService } $chore = $this->Database->chores($choreId); - $choreTrackedCount = $this->Database->chores_log()->where('chore_id', $choreId)->count(); - $choreLastTrackedTime = $this->Database->chores_log()->where('chore_id', $choreId)->max('tracked_time'); + $choreTrackedCount = $this->Database->chores_log()->where('chore_id = :1 AND undone = 0', $choreId)->count(); + $choreLastTrackedTime = $this->Database->chores_log()->where('chore_id = :1 AND undone = 0', $choreId)->max('tracked_time'); $nextExeuctionTime = $this->Database->chores_current()->where('chore_id', $choreId)->min('next_estimated_execution_time'); - $lastChoreLogRow = $this->Database->chores_log()->where('chore_id = :1 AND tracked_time = :2', $choreId, $choreLastTrackedTime)->fetch(); + $lastChoreLogRow = $this->Database->chores_log()->where('chore_id = :1 AND tracked_time = :2 AND undone = 0', $choreId, $choreLastTrackedTime)->fetch(); $lastDoneByUser = null; if ($lastChoreLogRow !== null && !empty($lastChoreLogRow)) { @@ -71,4 +71,19 @@ class ChoresService extends BaseService $choreRow = $this->Database->chores()->where('id = :1', $choreId)->fetch(); return $choreRow !== null; } + + public function UndoChoreExecution($executionId) + { + $logRow = $this->Database->chores_log()->where('id = :1 AND undone = 0', $executionId)->fetch(); + if ($logRow == null) + { + throw new \Exception('Execution does not exist or was already undone'); + } + + // Update log entry + $logRow->update(array( + 'undone' => 1, + 'undone_timestamp' => date('Y-m-d H:i:s') + )); + } }