From 93f77bfbb83373ffbbba6e1e9b75d5f48a06bd62 Mon Sep 17 00:00:00 2001 From: Aldarien Date: Wed, 22 Dec 2021 01:38:34 -0300 Subject: [PATCH] Upload files --- ui/Dockerfile | 4 + ui/common/Controller/Uploads.php | 24 ++ ui/composer.json | 11 +- ui/public/assets/scripts/uploads.list.js | 210 ++++++++++++++++++ ui/resources/routes/uploads.php | 10 + ui/resources/views/config/menu.blade.php | 1 + .../views/config/menu/files.blade.php | 4 + ui/resources/views/layout/body/menu.blade.php | 1 - ui/setup/setups/03_web.php | 30 ++- 9 files changed, 275 insertions(+), 20 deletions(-) create mode 100644 ui/common/Controller/Uploads.php create mode 100644 ui/public/assets/scripts/uploads.list.js create mode 100644 ui/resources/routes/uploads.php create mode 100644 ui/resources/views/config/menu/files.blade.php diff --git a/ui/Dockerfile b/ui/Dockerfile index 952159e..a7a3ff8 100644 --- a/ui/Dockerfile +++ b/ui/Dockerfile @@ -1,5 +1,9 @@ FROM php:8-fpm +RUN apt-get update -y && apt-get install -y git libzip-dev zip + +RUN docker-php-ext-install zip + COPY --from=composer /usr/bin/composer /usr/bin/composer WORKDIR /app diff --git a/ui/common/Controller/Uploads.php b/ui/common/Controller/Uploads.php new file mode 100644 index 0000000..c04cea0 --- /dev/null +++ b/ui/common/Controller/Uploads.php @@ -0,0 +1,24 @@ +render($response, 'uploads.list'); + } + public function get(Request $request, Response $response, Client $client, $folder, $filename): Response { + $resp = $client->get(implode('/', ['upload', $folder, $filename])); + $file = $resp->getBody(); + return $response + ->withHeader('Content-Type', $resp->getHeader('Content-Type')) + ->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); + } +} diff --git a/ui/composer.json b/ui/composer.json index 9cfd883..19237c5 100644 --- a/ui/composer.json +++ b/ui/composer.json @@ -8,7 +8,8 @@ "rubellum/slim-blade-view": "^0.1.1", "nyholm/psr7-server": "^1.0", "zeuxisoo/slim-whoops": "^0.7.3", - "nyholm/psr7": "^1.4" + "nyholm/psr7": "^1.4", + "guzzlehttp/guzzle": "^7.4" }, "require-dev": { "phpunit/phpunit": "^9.5", @@ -24,11 +25,5 @@ "psr-4": { "Contabilidad\\Common\\": "common" } - }, - "repositories": [ - { - "type": "git", - "url": "http://git.provm.cl/ProVM/controller.git" - } - ] + } } diff --git a/ui/public/assets/scripts/uploads.list.js b/ui/public/assets/scripts/uploads.list.js new file mode 100644 index 0000000..24094c3 --- /dev/null +++ b/ui/public/assets/scripts/uploads.list.js @@ -0,0 +1,210 @@ +class Archivo { + constructor({folder, filename}) { + this.folder = folder + this.filename = filename + this.modal = null + } + setModal(modal) { + this.modal = modal + return this + } + draw() { + return $('').append( + $('').append( + $('').attr('class', 'item').attr('href', _urls.base + ['upload', this.folder, this.filename].join('/')).html(this.filename) + ) + ).append( + $('').attr('class', 'right aligned').append( + $('').attr('class', 'ui mini circular icon button').append( + $('').attr('class', 'edit icon') + ).click((e) => { + e.preventDefault() + const t = e.currentTarget + this.edit() + return false + }) + ).append( + $('').attr('class', 'ui mini red circular icon button').append( + $('').attr('class', 'remove icon') + ).click((e) => { + e.preventDefault() + const t = e.currentTarget + this.remove() + return false + }) + ) + ) + } + edit() { + this.modal.find('form').trigger('reset') + this.modal.find('form').find("[name='folder']").val(this.folder) + this.modal.find('form').find("[name='old_filename']").val(this.filename) + this.modal.find('form').find("[name='filename']").val(this.filename) + this.modal.modal('show') + } + remove() { + return sendDelete([_urls.api, 'upload', this.folder, this.filename].join('/')).then((data) => { + if (data.deleted) { + archivos.get() + } + }) + } +} +const archivos = { + id: '#archivos', + archivos: [], + modals: { + add: null, + edit: null + }, + get: function() { + return { + parent: () => { + let parent = $(this.id).find('tbody') + if (parent.length === 0) { + const table = $('
').attr('class', 'ui striped table').append( + $('').append( + $('').append( + $('').html('Archivo') + ).append( + $('').attr('class', 'right aligned').append( + $('').attr('class', 'ui tiny green circular icon button').append( + $('').attr('class', 'plus icon') + ).click((e) => { + e.preventDefault() + this.add() + return false + }) + ) + ) + ) + ) + parent = $('') + table.append(parent) + $(this.id).append(table) + } + return parent + }, + archivos: () => { + return sendGet(_urls.api + '/uploads').then((data) => { + if (data.files === null || data.files.length === 0) { + return + } + $.each(data.files, (i, el) => { + const arch = new Archivo(el) + arch.setModal(this.modals.edit) + this.archivos.push(arch) + }) + }).then(() => { + this.draw() + }) + }, + cuentas: () => { + return sendGet(_urls.api + '/cuentas') + } + } + }, + draw: function() { + const tbody = this.get().parent() + tbody.html('') + $.each(this.archivos, (i, el) => { + tbody.append(el.draw()) + }) + }, + add: function() { + this.modals.add.find('form').trigger('reset') + this.modals.add.modal('show') + }, + doAdd: function() { + const data = new FormData(this.modals.add.find('form')) + return sendPost(_urls.api + '/categorias/add', data, true).then((resp) => { + this.modals.add.modal('hide') + this.getCategorias() + }) + }, + doEdit: function() { + const folder = this.modals.edit.find("[name='folder']").val() + const filename = this.modals.edit.find("[name='old_filename']").val() + const data = JSON.stringify({ + cuenta: this.modals.edit.find("[name='cuenta']").val(), + fecha: this.modals.edit.find("[name='fecha']").val() + }) + sendPut([_urls.api, 'upload', folder, filename].join('/'), data).then((resp) => { + this.modals.edit.modal('hide') + if (resp.edited) { + this.get().archivos() + } + }) + }, + updateCalendar: function(modal) { + const today = new Date() + const start = new Date(today.getFullYear(), today.getMonth() - 1) + modal.find('.ui.calendar').calendar({ + type: 'month', + initialDate: start, + maxDate: start, + months: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'], + monthsShort: ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'], + formatter: { + date: function(date, settings) { + if (!date) return '' + const year = date.getFullYear() + const month = date.getMonth() + 1 + return [year, month].join('-') + } + } + }) + }, + updateCuentas: function(modal, data) { + if (data.cuentas === null || data.cuentas.length === 0) { + return + } + const select = modal.find("select[name='cuenta']") + let values = [] + $.each(data.cuentas, (i, el) => { + const nombre = [el.nombre, el.categoria.nombre].join(' - ') + values.push({ + name: nombre, + value: el.id, + text: nombre + }) + }) + select.dropdown({values}) + }, + setupModal: function() { + this.modals.add = $('#add_modal') + this.modals.edit = $('#edit_modal') + $.each(this.modals, (i, el) => { + el.modal().find('.close.icon').click(() => { + el.modal('hide') + }) + this.updateCalendar(el) + }) + this.modals.add.find('form').submit((e) => { + e.preventDefault() + this.doAdd() + return false + }) + this.modals.add.find('#archivo_btn').css('cursor', 'pointer').click(() => { + this.modals.add.find("[name='archivo']").trigger('click') + }) + this.modals.add.find("[name='archivo']").change((e) => { + const arch = $(e.currentTarget) + const filename = arch[0].files[0].name + this.modals.add.find('#archivo_btn').find('input').val(filename) + }) + this.modals.edit.find('form').submit((e) => { + e.preventDefault() + this.doEdit() + return false + }) + this.get().cuentas().then((data) => { + this.updateCuentas(this.modals.add, data) + this.updateCuentas(this.modals.edit, data) + }) + }, + setup: function() { + this.setupModal() + this.get().archivos() + } +} diff --git a/ui/resources/routes/uploads.php b/ui/resources/routes/uploads.php new file mode 100644 index 0000000..af9cf9a --- /dev/null +++ b/ui/resources/routes/uploads.php @@ -0,0 +1,10 @@ +group('/uploads', function($app) { + $app->get('/add', [Uploads::class, 'upload']); + $app->get('[/]', Uploads::class); +}); +$app->group('/upload/{folder}/{filename}', function($app) { + $app->get('[/]', [Uploads::class, 'get']); +}); diff --git a/ui/resources/views/config/menu.blade.php b/ui/resources/views/config/menu.blade.php index c361fbe..6137067 100644 --- a/ui/resources/views/config/menu.blade.php +++ b/ui/resources/views/config/menu.blade.php @@ -1,4 +1,5 @@ diff --git a/ui/resources/views/config/menu/files.blade.php b/ui/resources/views/config/menu/files.blade.php new file mode 100644 index 0000000..daf9486 --- /dev/null +++ b/ui/resources/views/config/menu/files.blade.php @@ -0,0 +1,4 @@ + + Archivos + + diff --git a/ui/resources/views/layout/body/menu.blade.php b/ui/resources/views/layout/body/menu.blade.php index fb6e1c3..80944d6 100644 --- a/ui/resources/views/layout/body/menu.blade.php +++ b/ui/resources/views/layout/body/menu.blade.php @@ -2,7 +2,6 @@ Inicio @include('layout.body.menu.cuentas') @include('layout.body.menu.categorias') - Importar diff --git a/ui/setup/setups/03_web.php b/ui/setup/setups/03_web.php index 7ef8df1..0f5847a 100644 --- a/ui/setup/setups/03_web.php +++ b/ui/setup/setups/03_web.php @@ -2,15 +2,23 @@ use Psr\Container\ContainerInterface as Container; return [ - Slim\Views\Blade::class => function(Container $c) { - return new Slim\Views\Blade( - $c->get('folders')->templates, - $c->get('folders')->cache, - null, - [ - 'api_key' => $c->get('API_KEY'), - 'urls' => $c->get('urls') - ] - ); - } + Slim\Views\Blade::class => function(Container $c) { + return new Slim\Views\Blade( + $c->get('folders')->templates, + $c->get('folders')->cache, + null, + [ + 'api_key' => $c->get('API_KEY'), + 'urls' => $c->get('urls') + ] + ); + }, + GuzzleHttp\Client::class => function(Container $c) { + return new GuzzleHttp\Client([ + 'base_uri' => 'http://api-proxy', + 'headers' => [ + 'Authorization' => 'Bearer ' . $c->get('API_KEY') + ] + ]); + } ];