diff --git a/.idea/contabilidad.iml b/.idea/contabilidad.iml deleted file mode 100644 index 8558fe5..0000000 --- a/.idea/contabilidad.iml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/php.xml b/.idea/php.xml deleted file mode 100644 index e783343..0000000 --- a/.idea/php.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/api/common/Controller/Files.php b/api/common/Controller/Files.php new file mode 100644 index 0000000..6441a24 --- /dev/null +++ b/api/common/Controller/Files.php @@ -0,0 +1,77 @@ +listFiles(); + usort($files, function($a, $b) { + $f = strcmp($a->folder, $b->folder); + if ($f == 0) { + return strcmp($a->filename, $b->filename); + } + return $f; + }); + return $this->withJson($response, compact('files')); + } + public function upload(Request $request, Response $response, Handler $handler, Factory $factory): Response { + $post = $request->getParsedBody(); + $cuenta = $factory->find(Cuenta::class)->one($post['cuenta']); + $file = $request->getUploadedFiles()['archivo']; + $new_name = implode(' - ', [$cuenta->nombre, $cuenta->categoria()->nombre, $post['fecha']]); + $output = [ + 'input' => [ + 'name' => $file->getClientFilename(), + 'type' => $file->getClientMediaType(), + 'size' => $file->getSize(), + 'error' => $file->getError() + ], + 'new_name' => $new_name, + 'uploaded' => $handler->uploadFile($file, $new_name) + ]; + return $this->withJson($response, $output); + } + public function get(Request $request, Response $response, Handler $handler, $folder, $filename): Response { + $file = $handler->getFile($folder, $filename); + return $response + ->withHeader('Content-Type', $handler->getType($folder)) + ->withHeader('Content-Disposition', 'attachment; filename=' . $filename) + ->withAddedHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') + ->withHeader('Cache-Control', 'post-check=0, pre-check=0') + ->withHeader('Pragma', 'no-cache') + ->withBody($file); + } + public function edit(Request $request, Response $response, Handler $handler, Factory $factory, $folder, $filename): Response { + $post = json_decode($request->getBody()); + $cuenta = $factory->find(Cuenta::class)->one($post->cuenta); + $filenfo = $handler->getInfo($folder, $filename); + $new_name = implode('.', [implode(' - ', [$cuenta->nombre, $cuenta->categoria()->nombre, $post->fecha]), $filenfo->getExtension()]); + $output = [ + 'input' => [ + 'folder' => $folder, + 'filename' => $filename, + 'post' => $post + ], + 'edited' => $handler->editFilename($folder, $filename, $new_name) + ]; + return $this->withJson($response, $output); + } + public function delete(Request $request, Response $response, Handler $handler, $folder, $filename): Response { + $output = [ + 'input' => [ + 'folder' => $folder, + 'filename' => $filename + ], + 'deleted' => $handler->deleteFile($folder, $filename) + ]; + return $this->withJson($response, $output); + } +} diff --git a/api/common/Service/FileHandler.php b/api/common/Service/FileHandler.php new file mode 100644 index 0000000..5d06b1b --- /dev/null +++ b/api/common/Service/FileHandler.php @@ -0,0 +1,109 @@ +base_folder = $params->folder; + $this->addValidTypes(array_keys($params->types)); + $this->addFolders($params->types); + } + public function addFolders(array $folders): FileHandler { + foreach ($folders as $type => $folder) { + $this->addFolder($type, $folder); + } + return $this; + } + public function addFolder(string $type, string $folder): FileHandler { + $this->folders[$type] = $folder; + return $this; + } + public function addValidTypes(array $valid_types): FileHandler { + foreach ($valid_types as $type) { + $this->addValidType($type); + } + return $this; + } + public function addValidType(string $type): FileHandler { + $this->valid_types []= $type; + return $this; + } + public function getType(string $folder): string { + return array_search($folder, $this->folders); + } + + public function uploadFile(UploadedFileInterface $file, string $new_name = null): bool { + if ($file->getError() !== UPLOAD_ERR_OK) { + return false; + } + if (!in_array($file->getClientMediaType(), array_keys($this->valid_types))) { + return false; + } + if ($new_name === null) { + $new_name = $file->getClientFilename(); + } + $filenfo = new \SplFileInfo($file->getClientFilename()); + if (!str_contains($new_name, $filenfo->getExtension())) { + $new_name .= '.' . $filenfo->getExtension(); + } + $to = implode(DIRECTORY_SEPARATOR, [$this->base_folder, $this->folders[$file->getClientMediaType()], $new_name]); + $file->moveTo($to); + return file_exists($to); + } + public function listFiles(): array { + $output = []; + foreach ($this->folders as $f) { + $folder = implode(DIRECTORY_SEPARATOR, [$this->base_folder, $f]); + $files = new \DirectoryIterator($folder); + foreach ($files as $file) { + if ($file->isDir()) { + continue; + } + $output []= (object) ['folder' => $f, 'filename' => $file->getBasename()]; + } + } + return $output; + } + protected function validateFilename(string $folder, string $filename): bool|string { + if (!in_array($folder, $this->folders)) { + return false; + } + $f = implode(DIRECTORY_SEPARATOR, [$this->base_folder, $folder, $filename]); + if (!file_exists($f)) { + return false; + } + return $f; + } + public function getInfo(string $folder, string $filename): \SplFileInfo|bool { + if (!$f = $this->validateFilename($folder, $filename)) { + return false; + } + return new \SplFileInfo($f); + } + public function getFile(string $folder, string $filename): StreamInterface|bool { + if (!$f = $this->validateFilename($folder, $filename)) { + return false; + } + return Stream::create(file_get_contents($f)); + } + public function editFilename(string $folder, string $filename, string $new_name): bool { + if (!$f = $this->validateFilename($folder, $filename)) { + return false; + } + $info = new \SplFileInfo($f); + $new = implode(DIRECTORY_SEPARATOR, [$this->base_folder, $folder, $new_name . '.' . $info->getExtension()]); + return rename($f, $new); + } + public function deleteFile(string $folder, string $filename): bool { + if (!$f = $this->validateFilename($folder, $filename)) { + return false; + } + return unlink($f); + } +} diff --git a/api/nginx.conf b/api/nginx.conf index 5d96382..069343f 100644 --- a/api/nginx.conf +++ b/api/nginx.conf @@ -15,8 +15,7 @@ server { if ($request_method = 'OPTIONS') { add_header 'Access-Control-Max-Age' 1728000; add_header 'Access-Control-Allow-Origin' '*'; - add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent, - X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; + add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH'; add_header 'Content-Type' 'application/json'; add_header 'Content-Length' 0; @@ -24,8 +23,7 @@ server { } add_header 'Access-Control-Allow-Origin' '*'; - add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent, - X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; + add_header 'Access-Control-Allow-Headers' 'Authorization,Accept,Origin,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE,PATCH'; try_files $uri =404; diff --git a/api/public/uploads/pdfs/BICE-CC-2021-09.pdf b/api/public/uploads/pdfs/BICE-CC-2021-09.pdf deleted file mode 100644 index d521655..0000000 Binary files a/api/public/uploads/pdfs/BICE-CC-2021-09.pdf and /dev/null differ diff --git a/api/public/uploads/pdfs/Scotiabank-CC-2021-10.pdf b/api/public/uploads/pdfs/Scotiabank-CC-2021-10.pdf deleted file mode 100644 index 8fef2f3..0000000 Binary files a/api/public/uploads/pdfs/Scotiabank-CC-2021-10.pdf and /dev/null differ diff --git a/api/resources/routes/uploads.php b/api/resources/routes/uploads.php new file mode 100644 index 0000000..6138be8 --- /dev/null +++ b/api/resources/routes/uploads.php @@ -0,0 +1,12 @@ +group('/uploads', function($app) { + $app->post('/add[/]', [Files::class, 'upload']); + $app->get('[/]', Files::class); +}); +$app->group('/upload/{folder}/{filename}', function($app) { + $app->put('[/]', [Files::class, 'edit']); + $app->delete('[/]', [Files::class, 'delete']); + $app->get('[/]', [Files::class, 'get']); +}); diff --git a/api/setup/settings/02_common.php b/api/setup/settings/02_common.php index 1185ad3..eeb2bd9 100644 --- a/api/setup/settings/02_common.php +++ b/api/setup/settings/02_common.php @@ -19,7 +19,7 @@ return [ 'public' ]); $arr['uploads'] = implode(DIRECTORY_SEPARATOR, [ - $arr['public'], + $arr['base'], 'uploads' ]); $arr['pdfs'] = implode(DIRECTORY_SEPARATOR, [ diff --git a/api/setup/setups/02_common.php b/api/setup/setups/02_common.php index 27836d5..56eabc2 100644 --- a/api/setup/setups/02_common.php +++ b/api/setup/setups/02_common.php @@ -14,27 +14,27 @@ return [ $c->get(Contabilidad\Common\Service\Auth::class) ); }, - Contabilidad\Common\Service\PdfHandler::class => function(Container $c) { - return new Contabilidad\Common\Service\PdfHandler($c->get(GuzzleHttp\Client::class), $c->get('folders')->pdfs, implode('/', [ - $c->get('urls')->python, - 'pdf', - 'parse' - ])); - }, - Contabilidad\Common\Service\CsvHandler::class => function(Container $c) { - return new Contabilidad\Common\Service\CsvHandler($c->get('folders')->csvs); - }, - Contabilidad\Common\Service\XlsHandler::class => function(Container $c) { - return new Contabilidad\Common\Service\XlsHandler($c->get('folders')->xlss); - }, - Contabilidad\Common\Service\DocumentHandler::class => function(Container $c) { - $handlers = [ - $c->get(Contabilidad\Common\Service\XlsHandler::class), - $c->get(Contabilidad\Common\Service\CsvHandler::class), - $c->get(Contabilidad\Common\Service\PdfHandler::class) - ]; - return new Contabilidad\Common\Service\DocumentHandler($handlers); - }, + Contabilidad\Common\Service\PdfHandler::class => function(Container $c) { + return new Contabilidad\Common\Service\PdfHandler($c->get(GuzzleHttp\Client::class), $c->get('folders')->pdfs, implode('/', [ + $c->get('urls')->python, + 'pdf', + 'parse' + ])); + }, + Contabilidad\Common\Service\CsvHandler::class => function(Container $c) { + return new Contabilidad\Common\Service\CsvHandler($c->get('folders')->csvs); + }, + Contabilidad\Common\Service\XlsHandler::class => function(Container $c) { + return new Contabilidad\Common\Service\XlsHandler($c->get('folders')->xlss); + }, + Contabilidad\Common\Service\DocumentHandler::class => function(Container $c) { + $handlers = [ + $c->get(Contabilidad\Common\Service\XlsHandler::class), + $c->get(Contabilidad\Common\Service\CsvHandler::class), + $c->get(Contabilidad\Common\Service\PdfHandler::class) + ]; + return new Contabilidad\Common\Service\DocumentHandler($handlers); + }, Contabilidad\Common\Service\TiposCambios::class => function(Container $c) { return new Contabilidad\Common\Service\TiposCambios( $c->get(GuzzleHttp\Client::class), @@ -42,5 +42,17 @@ return [ $c->get('python_api'), $c->get('python_key') ); + }, + Contabilidad\Common\Service\FileHandler::class => function(Container $c) { + return new Contabilidad\Common\Service\FileHandler((object) [ + 'folder' => $c->get('folders')->uploads, + 'types' => [ + 'text/csv' => 'csvs', + 'application/pdf' => 'pdfs', + 'application/vnd.ms-excel' => 'xlss', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'xlss', + 'application/json' => 'jsons' + ] + ]); } ];