From b212381bb77233cb657c175a93129e89f4da8bff Mon Sep 17 00:00:00 2001 From: Juan Pablo Vial Date: Thu, 22 Jun 2023 23:15:17 -0400 Subject: [PATCH] Cli --- .db.env | 1 + aldarien/view/app/Contract/View.php | 11 +++- aldarien/view/app/Service/View.php | 4 +- app/Alias/Connection.php | 50 +++++++++++++++++ app/Alias/RemoteConnection.php | 59 +++----------------- app/Command/Money/Get.php | 86 +++++++++++++++++++++++++++++ app/Command/Money/Lookup.php | 51 +++++++++++++++++ app/Controller/Proyectos.php | 2 +- app/Service/Money.php | 1 + bin/console | 3 + bin/index.php | 8 +++ bootstrap/autoload.php | 1 + bootstrap/database.php | 1 - bootstrap/logs.php | 26 +++++++++ composer.json | 34 ++++++------ config/app.php | 1 - config/databases.php | 37 +++++++------ docker-compose.yml | 8 +++ public/api/index.php | 2 +- resources/routes/cli.php | 5 ++ setup/app.php | 5 ++ setup/cli.app.php | 48 ++++++++++++++++ setup/cli/config.php | 26 +++++++++ setup/cli/middlewares.php | 9 +++ setup/cli/setups.php | 43 +++++++++++++++ 25 files changed, 433 insertions(+), 89 deletions(-) create mode 100644 app/Alias/Connection.php create mode 100644 app/Command/Money/Get.php create mode 100644 app/Command/Money/Lookup.php create mode 100644 bin/console create mode 100644 bin/index.php create mode 100644 bootstrap/logs.php create mode 100644 resources/routes/cli.php create mode 100644 setup/cli.app.php create mode 100644 setup/cli/config.php create mode 100644 setup/cli/middlewares.php create mode 100644 setup/cli/setups.php diff --git a/.db.env b/.db.env index b88ed98..16b5aed 100644 --- a/.db.env +++ b/.db.env @@ -2,3 +2,4 @@ MYSQL_DATABASE=incoviba MYSQL_PASSWORD=5GQYFvRjVw2A4KcD MYSQL_ROOT_PASSWORD=password MYSQL_USER=incoviba +MYSQL_PORT=3307 diff --git a/aldarien/view/app/Contract/View.php b/aldarien/view/app/Contract/View.php index bf0d289..1d0c5b9 100644 --- a/aldarien/view/app/Contract/View.php +++ b/aldarien/view/app/Contract/View.php @@ -1,8 +1,12 @@ "http://{$remote->getIP()}:8008", + 'headers' => ['Accept' => 'application/json'] + ]))); + return new ViewService(['money' => $money]); } public static function show($template, $variables = null) { diff --git a/aldarien/view/app/Service/View.php b/aldarien/view/app/Service/View.php index 7c78bdd..7217696 100644 --- a/aldarien/view/app/Service/View.php +++ b/aldarien/view/app/Service/View.php @@ -9,12 +9,12 @@ class View protected $cache; protected $blade; - public function __construct() + public function __construct(array $variables = []) { $this->views = config('locations.views'); $this->cache = config('locations.cache'); - $this->blade = new BladeOne($this->views, $this->cache); + $this->blade = new BladeOne($this->views, $this->cache, null, $variables); } public function show($template, $vars = null) { diff --git a/app/Alias/Connection.php b/app/Alias/Connection.php new file mode 100644 index 0000000..1eea52a --- /dev/null +++ b/app/Alias/Connection.php @@ -0,0 +1,50 @@ +connection)) { + $r = 0; + $exception = null; + while ($r < $this->retries) { + try { + $dsn = $this->getDsn(); + $this->connection = new PDO($dsn, $this->username, $this->password); + return $this->connection; + } catch (PDOException $e) { + if ($exception !== null) { + $e = new PDOException($e->getMessage(), $e->getCode(), $exception); + } + $exception = $e; + usleep(500); + } + $r ++; + } + throw $exception; + } + return $this->connection; + } + protected function getDsn(): string + { + $dsn = "mysql:host={$this->host};dbname={$this->database}"; + if (isset($this->port)) { + $dsn .= ";port={$this->port}"; + } + return $dsn; + } +} diff --git a/app/Alias/RemoteConnection.php b/app/Alias/RemoteConnection.php index 20d0d25..475225e 100644 --- a/app/Alias/RemoteConnection.php +++ b/app/Alias/RemoteConnection.php @@ -1,58 +1,17 @@ host = $_ENV['REMOTE_HOST']; - $this->database = $_ENV['REMOTE_DATABASE']; - $this->username = $_ENV['REMOTE_USER']; - $this->password = $_ENV['REMOTE_PASSWORD']; - if (isset($_ENV['REMOTE_PORT'])) { - $this->port = $_ENV['REMOTE_PORT']; - } - } - - protected string $host; - protected string $database; - protected int $port; - protected string $username; - protected string $password; - - protected PDO $connection; - public function connect(): PDO - { - if (!isset($this->connection)) { - $r = 0; - $exception = null; - while ($r < $this->retries) { - try { - $dsn = $this->getDsn(); - $this->connection = new PDO($dsn, $this->username, $this->password); - } catch (PDOException $e) { - if ($exception !== null) { - $e = new PDOException($e->getMessage(), $e->getCode(), $exception); - } - $exception = $e; - usleep(500); - } - $r ++; - } - throw $exception; - } - return $this->connection; - } - - protected function getDsn(): string - { - $dsn = "mysql:host={$this->host};dbname={$this->database}"; - if (isset($this->port)) { - $dsn .= ";port={$this->port}"; - } - return $dsn; + parent::__construct( + $_ENV['REMOTE_HOST'], + $_ENV['REMOTE_DATABASE'], + $_ENV['REMOTE_USER'], + $_ENV['REMOTE_PASSWORD'], + $_ENV['REMOTE_PORT'] ?? null, + $this->retries + ); } } diff --git a/app/Command/Money/Get.php b/app/Command/Money/Get.php new file mode 100644 index 0000000..9228582 --- /dev/null +++ b/app/Command/Money/Get.php @@ -0,0 +1,86 @@ +title('Get Money'); + + $dates = $this->getDates(); + foreach ($dates as $date_string => $ids) { + $date = $this->parseDate($date_string); + $response = $this->service->getUF($date); + if ($response->total === 0) { + continue; + } + foreach ($ids as $id) { + $this->queueUpdate($id, $response->uf->value); + } + } + $this->updateUF(); + } + + protected function getDates(): array + { + $query = "SELECT id, fecha FROM pago WHERE uf IS NULL AND fecha BETWEEN 0 AND DATE_ADD(CURDATE(), INTERVAL 9 DAY) ORDER BY fecha"; + $statement = $this->connection->connect()->query($query); + $rows = $statement->fetchAll(PDO::FETCH_ASSOC); + if (count($rows) === 0) { + return []; + } + $dates = []; + foreach ($rows as $row) { + if (!isset($dates[$row['fecha']])) { + $dates[$row['fecha']] = []; + } + $dates[$row['fecha']] []= (int) $row['id']; + } + return $dates; + } + protected function parseDate(string $date_string): DateTimeInterface + { + return new DateTimeImmutable($date_string); + } + protected array $rows; + protected function queueUpdate(int $id, float $value): void + { + $this->rows []= [$value, $id]; + } + protected function updateUF(): void + { + $query = "UPDATE pago SET uf = ? WHERE id = ?"; + $statement = $this->connection->connect()->prepare($query); + foreach ($this->rows as $row) { + $this->connection->connect()->beginTransaction(); + try { + $statement->execute($row); + $this->connection->connect()->commit(); + } catch (PDOException $e) { + $this->connection->connect()->rollBack(); + } + } + } +} diff --git a/app/Command/Money/Lookup.php b/app/Command/Money/Lookup.php new file mode 100644 index 0000000..43b85b9 --- /dev/null +++ b/app/Command/Money/Lookup.php @@ -0,0 +1,51 @@ +title('Lookup Money'); + + while (true) { + $io->info('Checking pending'); + if ($this->hasPendingMoney()) { + $io->success('Running money get UF'); + $io->note($this->runGetUF()); + } + } + } + + protected function hasPendingMoney(): bool + { + $query = "SELECT 1 FROM pago WHERE uf IS NULL AND fecha BETWEEN 0 AND DATE_ADD(CURDATE(), INTERVAL 9 DAY)"; + $statement = $this->connection->connect()->query($query); + return $statement->rowCount() > 0; + } + protected function runGetUF(): string + { + $command = "/code/bin/console money:uf:get"; + $result = shell_exec($command); + if (!$result or $result === null) { + throw new \Exception(); + } + return $result; + } +} diff --git a/app/Controller/Proyectos.php b/app/Controller/Proyectos.php index f6a4e45..9c69ad5 100644 --- a/app/Controller/Proyectos.php +++ b/app/Controller/Proyectos.php @@ -312,7 +312,7 @@ class Proyectos } return view('proyectos.reservas.base', compact('proyecto', 'pisos', 'max_unidades', 'totales')); } - public function unidades() + public static function unidades() { if (get('proyecto')) { $proyecto = model(Proyecto::class)->findOne(get('proyecto')); diff --git a/app/Service/Money.php b/app/Service/Money.php index f0a2204..2472e62 100644 --- a/app/Service/Money.php +++ b/app/Service/Money.php @@ -40,6 +40,7 @@ class Money protected function checkNextMonthValueCalculationByDate(DateTimeInterface $date): bool { $next_m_9 = Carbon::today(config('app.timezone'))->copy()->endOfMonth()->addDays(9); + $date = Carbon::parse($date); return $date->lessThan($next_m_9); } protected function isOk(ResponseInterface $response): bool diff --git a/bin/console b/bin/console new file mode 100644 index 0000000..11aaaef --- /dev/null +++ b/bin/console @@ -0,0 +1,3 @@ +#!/bin/bash + +php /code/bin/index.php "$@" diff --git a/bin/index.php b/bin/index.php new file mode 100644 index 0000000..f5683c7 --- /dev/null +++ b/bin/index.php @@ -0,0 +1,8 @@ +run(); diff --git a/bootstrap/autoload.php b/bootstrap/autoload.php index 7595f12..318f80d 100644 --- a/bootstrap/autoload.php +++ b/bootstrap/autoload.php @@ -1,6 +1,7 @@ diff --git a/bootstrap/logs.php b/bootstrap/logs.php new file mode 100644 index 0000000..249be53 --- /dev/null +++ b/bootstrap/logs.php @@ -0,0 +1,26 @@ + false, 'login_hours' => 5*24 ]; -?> diff --git a/config/databases.php b/config/databases.php index 660d432..14e279f 100644 --- a/config/databases.php +++ b/config/databases.php @@ -1,19 +1,24 @@ [ - 'host' => $_ENV['MYSQL_HOST'], - //'port' => 3306, - 'database' => $_ENV['MYSQL_DATABASE'], - 'username' => $_ENV['MYSQL_USER'], - 'password' => $_ENV['MYSQL_PASSWORD'] - ], - 'mysql_copy' => [ - 'host' => 'localhost', - 'database' => 'incoviba3', - 'username' => 'incoviba', - 'password' => $_ENV['MYSQL_PASSWORD'] - ] -] -?> +function buildDatabaseConfig(): array { + $arr = [ + 'mysql' => [ + 'host' => $_ENV['MYSQL_HOST'], + 'database' => $_ENV['MYSQL_DATABASE'], + 'username' => $_ENV['MYSQL_USER'], + 'password' => $_ENV['MYSQL_PASSWORD'] + ], + 'mysql_copy' => [ + 'host' => 'localhost', + 'database' => 'incoviba3', + 'username' => 'incoviba', + 'password' => $_ENV['MYSQL_PASSWORD'] + ] + ]; + if (isset($_ENV['MYSQL_PORT'])) { + $arr['mysql']['port'] = $_ENV['MYSQL_PORT']; + } + return $arr; +} +return buildDatabaseConfig(); diff --git a/docker-compose.yml b/docker-compose.yml index cd63df6..4052376 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,6 +25,7 @@ services: env_file: - .env - .db.env + - .remote.env volumes: - .:/code - ./php-errors.ini:/usr/local/etc/php/conf.d/docker-php-errors.ini @@ -39,6 +40,9 @@ services: env_file: .db.env volumes: - dbdata:/var/lib/mysql + networks: + - default + - adminer_network adminer: profiles: @@ -68,6 +72,7 @@ services: container_name: incoviba_logview restart: unless-stopped environment: + WEB_URL: 'http://provm.cl:8084' WEB_PORT: '8084' volumes: - "./logs:/logs" @@ -76,3 +81,6 @@ services: volumes: dbdata: + +networks: + adminer_network: {} diff --git a/public/api/index.php b/public/api/index.php index 223ef89..cec7741 100644 --- a/public/api/index.php +++ b/public/api/index.php @@ -1,6 +1,6 @@ add($app->getContainer()->get(Command\Money\Lookup::class)); +$app->add($app->getContainer()->get(Command\Money\Get::class)); diff --git a/setup/app.php b/setup/app.php index d2e8644..42a9b0e 100644 --- a/setup/app.php +++ b/setup/app.php @@ -9,6 +9,9 @@ $folders = [ 'setups' ]; $builder = new Builder(); +if (isset($__environment)) { + $builder->addDefinitions(['environment' => $__environment]); +} foreach ($folders as $f) { $folder = implode(DIRECTORY_SEPARATOR, [ __DIR__, @@ -50,3 +53,5 @@ $app->addErrorMiddleware(true, true, true); include_once 'database.php'; include_once 'router.php'; + +return $app; diff --git a/setup/cli.app.php b/setup/cli.app.php new file mode 100644 index 0000000..5406139 --- /dev/null +++ b/setup/cli.app.php @@ -0,0 +1,48 @@ +addDefinitions($filename); +} +$app = new class() extends Application +{ + protected ContainerInterface $container; + public function getContainer(): ContainerInterface + { + return $this->container; + } + public function setContainer(ContainerInterface $container) + { + $this->container = $container; + return $this; + } +}; +$app->setContainer($builder->build()); + +$filename = implode(DIRECTORY_SEPARATOR, [ + __DIR__, + 'cli', + 'middlewares.php' +]); +if (file_exists($filename)) { + include_once $filename; +} + +return $app; diff --git a/setup/cli/config.php b/setup/cli/config.php new file mode 100644 index 0000000..7760f90 --- /dev/null +++ b/setup/cli/config.php @@ -0,0 +1,26 @@ + function() { + $container = new DI\Container([ + ORM::DEFAULT_CONNECTION => new DI\Container([ + 'host' => $_ENV['MYSQL_HOST'], + 'database' => $_ENV['MYSQL_DATABASE'], + 'username' => $_ENV['MYSQL_USER'], + 'password' => $_ENV['MYSQL_PASSWORD'] + ]), + 'remote' => new DI\Container([ + 'host' => $_ENV['REMOTE_HOST'], + 'database' => $_ENV['REMOTE_DATABASE'], + 'username' => $_ENV['REMOTE_USER'], + 'password' => $_ENV['REMOTE_PASSWORD'] + ]) + ]); + if (isset($_ENV['MYSQL_PORT'])) { + $container->get(ORM::DEFAULT_CONNECTION)->set('port', $_ENV['MYSQL_PORT']); + } + if (isset($_ENV['REMOTE_PORT'])) { + $container->get('remote')->set('port', $_ENV['REMOTE_PORT']); + } + return $container; + } +]; diff --git a/setup/cli/middlewares.php b/setup/cli/middlewares.php new file mode 100644 index 0000000..b8068c4 --- /dev/null +++ b/setup/cli/middlewares.php @@ -0,0 +1,9 @@ +getContainer()->get(Psr\Log\LoggerInterface::class)); diff --git a/setup/cli/setups.php b/setup/cli/setups.php new file mode 100644 index 0000000..33b847a --- /dev/null +++ b/setup/cli/setups.php @@ -0,0 +1,43 @@ + function(ContainerInterface $container) { + return new Monolog\Logger('cli', [ + new Monolog\Handler\FilterHandler(new Monolog\Handler\RotatingFileHandler('/logs/cli.debug.log'), Monolog\Level::Debug, Monolog\Level::Notice), + new Monolog\Handler\FilterHandler(new Monolog\Handler\RotatingFileHandler('/logs/cli.error.log'), Monolog\Level::Warning) + ], [ + new Monolog\Processor\PsrLogMessageProcessor(), + new Monolog\Processor\IntrospectionProcessor(), + new Monolog\Processor\MemoryUsageProcessor(), + new Monolog\Processor\MemoryPeakUsageProcessor() + ]); + }, + GuzzleHttp\Client::class => function(ContainerInterface $container) { + return new GuzzleHttp\Client([ + 'base_uri' => "http://{$container->get(App\Service\Remote::class)->getIP()}:8008", + 'headers' => [ + 'Accept' => 'application/json' + ] + ]); + }, + App\Alias\RemoteConnection::class => function(ContainerInterface $container) { + return new App\Alias\RemoteConnection(); + }, + App\Service\Remote::class => function(ContainerInterface $container) { + return new App\Service\Remote($container->get(App\Alias\RemoteConnection::class)); + }, + App\Service\Money::class => function(ContainerInterface $container) { + return new App\Service\Money($container->get(GuzzleHttp\Client::class)); + }, + App\Alias\Connection::class => function(ContainerInterface $container) { + $data = $container->get('databases')->get(ORM::DEFAULT_CONNECTION); + return new App\Alias\Connection( + $data->get('host'), + $data->get('database'), + $data->get('username'), + $data->get('password'), + $data->has('port') ? $data->get('port') : null + ); + }, +];