diff --git a/controllers/FilesApiController.php b/controllers/FilesApiController.php index 91192e47..656ecc09 100644 --- a/controllers/FilesApiController.php +++ b/controllers/FilesApiController.php @@ -29,6 +29,40 @@ class FilesApiController extends BaseApiController $data = $request->getBody()->getContents(); file_put_contents($this->FilesService->GetFilePath($args['group'], $fileName), $data); + + return $this->ApiResponse(array('success' => true)); + } + catch (\Exception $ex) + { + return $this->VoidApiActionResponse($response, false, 400, $ex->getMessage()); + } + } + + public function ServeFile(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args) + { + try + { + if (isset($request->getQueryParams()['file_name']) && !empty($request->getQueryParams()['file_name']) && IsValidFileName($request->getQueryParams()['file_name'])) + { + $fileName = $request->getQueryParams()['file_name']; + } + else + { + throw new \Exception('file_name query parameter missing or contains an invalid filename'); + } + + $filePath = $this->FilesService->GetFilePath($args['group'], $fileName); + + if (file_exists($filePath)) + { + $response->write(file_get_contents($filePath)); + $response = $response->withHeader('Content-Type', mime_content_type($filePath)); + return $response->withHeader('Content-Disposition', 'inline; filename="' . $fileName . '"'); + } + else + { + return $this->VoidApiActionResponse($response, false, 404, 'File not found'); + } } catch (\Exception $ex) { diff --git a/grocy.openapi.json b/grocy.openapi.json index e2bbee91..d50fd8f2 100644 --- a/grocy.openapi.json +++ b/grocy.openapi.json @@ -491,6 +491,57 @@ } } }, + "/files/get/{group}": { + "get": { + "description": "Serves the given file", + "tags": [ + "Files" + ], + "parameters": [ + { + "in": "path", + "name": "group", + "required": true, + "description": "The file group", + "schema": { + "type": "string" + } + }, + { + "in": "query", + "name": "file_name", + "required": true, + "description": "The file name (including extension)", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "The binary file contents (mime type is set based on file extension)", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "description": "A VoidApiActionResponse object", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorExampleVoidApiActionResponse" + } + } + } + } + } + } + }, "/users/get": { "get": { "description": "Returns all users", diff --git a/middleware/JsonMiddleware.php b/middleware/JsonMiddleware.php index a20f0ed9..9e7cb635 100644 --- a/middleware/JsonMiddleware.php +++ b/middleware/JsonMiddleware.php @@ -7,6 +7,14 @@ class JsonMiddleware extends BaseMiddleware public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next) { $response = $next($request, $response); - return $response->withHeader('Content-Type', 'application/json'); + + if ($response->hasHeader('Content-Disposition')) + { + return $response; + } + else + { + return $response->withHeader('Content-Type', 'application/json'); + } } } diff --git a/routes.php b/routes.php index 25404d49..873b899e 100644 --- a/routes.php +++ b/routes.php @@ -85,6 +85,7 @@ $app->group('/api', function() // Files $this->post('/files/upload/{group}', '\Grocy\Controllers\FilesApiController:Upload'); + $this->get('/files/get/{group}', '\Grocy\Controllers\FilesApiController:ServeFile'); // Users $this->get('/users/get', '\Grocy\Controllers\UsersApiController:GetUsers');