Browse Source

Add conversion routine.

pull/1/head
James Cole 4 years ago
parent
commit
9d30111f50
No known key found for this signature in database GPG Key ID: BDE6667570EADBD5
  1. 1
      app/Http/Controllers/Import/ConfigurationController.php
  2. 153
      app/Http/Controllers/Import/ConversionController.php
  3. 68
      app/Services/CSV/Configuration/Configuration.php
  4. 126
      app/Services/CSV/Conversion/RoutineManager.php
  5. 2
      app/Services/Import/ImportJobStatus/ImportJobStatusManager.php
  6. 1
      app/Services/Import/ImportRoutineManager.php
  7. 4
      app/Services/Session/Constants.php
  8. 84
      app/Services/Shared/Conversion/ConversionStatus.php
  9. 47
      app/Services/Shared/Conversion/RoutineManagerInterface.php
  10. 205
      app/Services/Shared/Conversion/RoutineStatusManager.php
  11. 4
      config/filesystems.php
  12. 4
      resources/views/index.twig
  13. 8
      routes/web.php
  14. 2
      storage/conversion-routines/.gitignore

1
app/Http/Controllers/Import/ConfigurationController.php

@ -146,6 +146,7 @@ class ConfigurationController extends Controller
// store config on drive.
$fromRequest = $request->getAll();
$configuration = Configuration::fromRequest($fromRequest);
$configuration->setFlow($request->cookie('flow'));
$json = '[]';
try {

153
app/Http/Controllers/Import/CSV/ConvertController.php → app/Http/Controllers/Import/ConversionController.php

@ -22,7 +22,7 @@
declare(strict_types=1);
namespace App\Http\Controllers\Import\CSV;
namespace App\Http\Controllers\Import;
use App\Exceptions\ImporterErrorException;
@ -30,24 +30,24 @@ use App\Http\Controllers\Controller;
use App\Http\Middleware\ReadyForImport;
use App\Mail\ImportFinished;
use App\Services\CSV\Configuration\Configuration;
use App\Services\CSV\File\FileReader;
use App\Services\CSV\Conversion\RoutineManager as CSVRoutineManager;
use App\Services\Import\ImportJobStatus\ImportJobStatus;
use App\Services\Import\ImportJobStatus\ImportJobStatusManager;
use App\Services\Import\ImportRoutineManager;
use App\Services\Session\Constants;
use App\Services\Shared\Conversion\ConversionStatus;
use App\Services\Shared\Conversion\RoutineManagerInterface;
use App\Services\Shared\Conversion\RoutineStatusManager;
use App\Services\Storage\StorageService;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use JsonException;
use Log;
use Mail;
use TypeError;
/**
* Class ConvertController
* Class ConversionController
*/
class ConvertController extends Controller
class ConversionController extends Controller
{
/**
@ -67,7 +67,6 @@ class ConvertController extends Controller
{
Log::debug(sprintf('Now in %s', __METHOD__));
$mainTitle = 'Import the data';
$subTitle = 'Connect to Firefly III and store your data';
// get configuration object.
$configuration = Configuration::fromArray(session()->get(Constants::CONFIGURATION));
@ -77,7 +76,6 @@ class ConvertController extends Controller
if (null !== $configFileName) {
$diskArray = json_decode(StorageService::getContent(session()->get($configFileName)), true, JSON_THROW_ON_ERROR);
$diskConfig = Configuration::fromArray($diskArray);
$configuration->setDoMapping($diskConfig->getDoMapping());
$configuration->setMapping($diskConfig->getMapping());
}
@ -96,80 +94,113 @@ class ConvertController extends Controller
}
// job ID may be in session:
$identifier = session()->get(Constants::CSV_CONVERSION_JOB_IDENTIFIER);
$routine = new ImportRoutineManager($identifier);
$identifier = session()->get(Constants::CONVERSION_JOB_IDENTIFIER);
$flow = $configuration->getFlow();
// switch based on flow:
if (!in_array($flow, config('importer.flows'), true)) {
throw new ImporterErrorException(sprintf('Not a supported flow: "%s"', $flow));
}
/** @var RoutineManagerInterface $routine */
if ('csv' === $flow) {
$routine = new CSVRoutineManager(null);
}
if ('nordigen' === $flow) {
throw new ImporterErrorException('Cannot handle. :(');
}
if ('spectre' === $flow) {
throw new ImporterErrorException('Cannot handle. :(');
}
// may be a new identifier! Yay!
$identifier = $routine->getIdentifier();
Log::debug(sprintf('Import routine manager identifier is "%s"', $identifier));
Log::debug(sprintf('Conversion routine manager identifier is "%s"', $identifier));
// store identifier in session so the status can get it.
session()->put(Constants::CSV_CONVERSION_JOB_IDENTIFIER, $identifier);
Log::debug(sprintf('Stored "%s" under "%s"', $identifier, Constants::CSV_CONVERSION_JOB_IDENTIFIER));
session()->put(Constants::CONVERSION_JOB_IDENTIFIER, $identifier);
Log::debug(sprintf('Stored "%s" under "%s"', $identifier, Constants::CONVERSION_JOB_IDENTIFIER));
return view('import.007-convert.index', compact('mainTitle', 'subTitle', 'identifier', 'jobBackUrl'));
return view('import.007-convert.index', compact('mainTitle', 'identifier', 'jobBackUrl'));
}
/**
* @param Request $request
*
* @return JsonResponse
* @throws JsonException
* @throws JsonException
*/
public function start(Request $request): JsonResponse
{
Log::debug(sprintf('Now at %s', __METHOD__));
$identifier = $request->get('identifier');
$routine = new ImportRoutineManager($identifier);
$importJobStatus = ImportJobStatusManager::startOrFindJob($identifier);
ImportJobStatusManager::setJobStatus(ImportJobStatus::JOB_RUNNING);
// start new conversion routine, depending on the type of import:
// read configuration from session
$configuration = Configuration::fromArray(session()->get(Constants::CONFIGURATION));
try {
// read configuration from session
$configuration = Configuration::fromArray(session()->get(Constants::CONFIGURATION));
// read configuration from disk (to append data)
$configurationFile = session()->get(Constants::UPLOAD_CONFIG_FILE);
if (null !== $configurationFile) {
$diskArray = json_decode(StorageService::getContent($configurationFile), true, JSON_THROW_ON_ERROR);
$diskConfig = Configuration::fromArray($diskArray);
$configuration->setMapping($diskConfig->getMapping());
$configuration->setDoMapping($diskConfig->getDoMapping());
$configuration->setRoles($diskConfig->getRoles());
}
// read configuration from disk (to append data)
$configurationFile = session()->get(Constants::UPLOAD_CONFIG_FILE);
if (null !== $configurationFile) {
$diskArray = json_decode(StorageService::getContent($configurationFile), true, JSON_THROW_ON_ERROR);
$diskConfig = Configuration::fromArray($diskArray);
$configuration->setMapping($diskConfig->getMapping());
$configuration->setDoMapping($diskConfig->getDoMapping());
$configuration->setRoles($diskConfig->getRoles());
}
$routine->setConfiguration($configuration);
$routine->setReader(FileReader::getReaderFromSession());
$routine->start();
} /** @noinspection PhpRedundantCatchClauseInspection */ catch (ImporterErrorException | ErrorException | TypeError $e) {
// update job to error state.
ImportJobStatusManager::setJobStatus(ImportJobStatus::JOB_ERRORED);
$error = sprintf('Internal error: %s in file %s:%d', $e->getMessage(), $e->getFile(), $e->getLine());
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
ImportJobStatusManager::addError($identifier, 0, $error);
return response()->json($importJobStatus->toArray());
// now create the right class:
$flow = $configuration->getFlow();
if (!in_array($flow, config('importer.flows'), true)) {
throw new ImporterErrorException(sprintf('Not a supported flow: "%s"', $flow));
}
/** @var RoutineManagerInterface $routine */
if ('csv' === $flow) {
$routine = new CSVRoutineManager($identifier);
}
if ('nordigen' === $flow) {
throw new ImporterErrorException('Cannot handle. :(');
}
if ('spectre' === $flow) {
throw new ImporterErrorException('Cannot handle. :(');
}
// set done:
ImportJobStatusManager::setJobStatus(ImportJobStatus::JOB_DONE);
// if configured, send report!
$log
= [
'messages' => $routine->getAllMessages(),
'warnings' => $routine->getAllWarnings(),
'errors' => $routine->getAllErrors(),
];
$send = config('mail.enable_mail_report');
Log::debug('Log log', $log);
if (true === $send) {
Log::debug('SEND MAIL');
Mail::to(config('mail.destination'))->send(new ImportFinished($log));
$importJobStatus = RoutineStatusManager::startOrFindConversion($identifier);
RoutineStatusManager::setConversionStatus(ConversionStatus::CONVERSION_RUNNING);
// then push stuff into the routine:
$routine->setConfiguration($configuration);
//$routine->setReader(FileReader::getReaderFromSession());
$result = false;
try {
$routine->start();
$result = true;
} catch (ImporterErrorException $e) {
RoutineStatusManager::setConversionStatus(ConversionStatus::CONVERSION_ERRORED);
}
die('here we are');
if (true === $result) {
// set done:
RoutineStatusManager::setConversionStatus(ConversionStatus::CONVERSION_DONE);
// if configured, send report!
// TODO make event handler.
$log
= [
'messages' => $routine->getAllMessages(),
'warnings' => $routine->getAllWarnings(),
'errors' => $routine->getAllErrors(),
];
$send = config('mail.enable_mail_report');
Log::debug('Log log', $log);
if (true === $send) {
Log::debug('SEND MAIL');
Mail::to(config('mail.destination'))->send(new ImportFinished($log));
}
}
return response()->json($importJobStatus->toArray());
}

68
app/Services/CSV/Configuration/Configuration.php

@ -34,7 +34,7 @@ use UnexpectedValueException;
class Configuration
{
/** @var int */
public const VERSION = 2;
public const VERSION = 3;
private string $date;
private int $defaultAccount;
private string $delimiter;
@ -47,6 +47,9 @@ class Configuration
private array $doMapping;
private bool $addImportTag;
// what type of import?
private string $flow;
// how to do double transaction detection?
private array $mapping; // 'classic' or 'cell'
@ -75,6 +78,7 @@ class Configuration
$this->roles = [];
$this->mapping = [];
$this->doMapping = [];
$this->flow = 'csv';
// double transaction detection:
$this->duplicateDetectionMethod = 'classic';
@ -132,6 +136,9 @@ class Configuration
$object->uniqueColumnIndex = $array['unique_column_index'] ?? 0;
$object->uniqueColumnType = $array['unique_column_type'] ?? '';
// flow
$object->flow = $array['flow'] ?? 'csv';
// overrule a setting:
if ('none' === $object->duplicateDetectionMethod) {
$object->ignoreDuplicateTransactions = false;
@ -166,6 +173,12 @@ class Configuration
return self::fromVersionTwo($data);
}
if (3 === $version) {
Log::debug('v3 config file!');
return self::fromVersionThree($data);
}
throw new UnexpectedValueException(sprintf('Configuration file version "%s" cannot be parsed.', $version));
}
@ -184,6 +197,7 @@ class Configuration
$object->delimiter = $delimiters[$data['delimiter']] ?? 'comma';
$object->defaultAccount = $data['import-account'] ?? $object->defaultAccount;
$object->rules = $data['apply-rules'] ?? true;
$object->flow = $data['flow'] ?? 'csv';
$object->ignoreDuplicateTransactions = $data['ignore_duplicate_transactions'] ?? true;
@ -262,6 +276,18 @@ class Configuration
return self::fromArray($data);
}
/**
* @param array $data
*
* @return static
*/
private static function fromVersionThree(array $data): self
{
$object = self::fromArray($data);
$object->specifics = [];
return $object;
}
/**
* @param array $array
*
@ -279,11 +305,11 @@ class Configuration
$object->rules = $array['rules'];
$object->skipForm = $array['skip_form'];
$object->addImportTag = $array['add_import_tag'] ?? true;
$object->specifics = $array['specifics'];
$object->roles = $array['roles'] ?? [];
$object->mapping = $array['mapping'] ?? [];
$object->doMapping = $array['do_mapping'] ?? [];
$object->version = $version;
$object->flow = $array['flow'] ?? 'csv';
// duplicate transaction detection
$object->duplicateDetectionMethod = $array['duplicate_detection_method'] ?? 'classic';
@ -308,24 +334,6 @@ class Configuration
$object->uniqueColumnIndex = $array['unique_column_index'] ?? 0;
$object->uniqueColumnType = $array['unique_column_type'] ?? '';
$firstValue = count(array_values($array['specifics'])) > 0 ? array_values($array['specifics'])[0] : null;
$firstKey = count(array_values($array['specifics'])) > 0 ? array_keys($array['specifics'])[0] : null;
// due to a bug, the "specifics" array could still be broken at this point.
// do a quick check and verification.
if (is_bool($firstValue) && is_string($firstKey)) {
$actualSpecifics = [];
foreach ($array['specifics'] as $key => $value) {
if (true === $value) {
$actualSpecifics[] = $key;
}
}
$object->specifics = $actualSpecifics;
}
//Log::debug(var_export($object->ignoreDuplicateLines, true));
//Log::debug(var_export($object->ignoreDuplicateTransactions, true));
return $object;
}
@ -411,7 +419,6 @@ class Configuration
'rules' => $this->rules,
'skip_form' => $this->skipForm,
'add_import_tag' => $this->addImportTag,
'specifics' => $this->specifics,
'roles' => $this->roles,
'do_mapping' => $this->doMapping,
'mapping' => $this->mapping,
@ -421,6 +428,7 @@ class Configuration
'unique_column_index' => $this->uniqueColumnIndex,
'unique_column_type' => $this->uniqueColumnType,
'version' => $this->version,
'flow' => $this->flow,
];
// make sure that "ignore duplicate transactions" is turned off
@ -503,7 +511,7 @@ class Configuration
public function setMapping(array $mapping): void
{
$newMap = [];
foreach($mapping as $column => $map) {
foreach ($mapping as $column => $map) {
ksort($map);
$newMap[$column] = $map;
}
@ -542,5 +550,21 @@ class Configuration
return $this->uniqueColumnType;
}
/**
* @return string
*/
public function getFlow(): string
{
return $this->flow;
}
/**
* @param string $flow
*/
public function setFlow(string $flow): void
{
$this->flow = $flow;
}
}

126
app/Services/CSV/Conversion/RoutineManager.php

@ -0,0 +1,126 @@
<?php
/*
* RoutineManager.php
* Copyright (c) 2021 james@firefly-iii.org
*
* This file is part of the Firefly III Data Importer
* (https://github.com/firefly-iii/data-importer).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace App\Services\CSV\Conversion;
use App\Services\CSV\Configuration\Configuration;
use App\Services\Import\Routine\CSVFileProcessor;
use App\Services\Shared\Conversion\RoutineManagerInterface;
use Log;
use Storage;
use Str;
/**
* Class RoutineManager
*/
class RoutineManager implements RoutineManagerInterface
{
private const DISK_NAME = 'conversion-routines';
private Configuration $configuration;
private string $identifier;
private CSVFileProcessor $csvFileProcessor;
/**
*
*/
public function __construct(?string $identifier)
{
if (null === $identifier) {
$this->generateIdentifier();
}
if (null !== $identifier) {
$this->identifier = $identifier;
}
}
/**
* @inheritDoc
*/
public function setConfiguration(Configuration $configuration): void
{
// save config
$this->configuration = $configuration;
// share config
$this->csvFileProcessor = new CSVFileProcessor($this->configuration);
// set identifier:
$this->csvFileProcessor->setIdentifier($this->identifier);
}
/**
* @inheritDoc
*/
public function start(): void
{
Log::debug(sprintf('Now in %s', __METHOD__));
// convert CSV file into raw lines (arrays)
$this->csvFileProcessor->setSpecifics($this->configuration->getSpecifics());
$this->csvFileProcessor->setHasHeaders($this->configuration->isHeaders());
$this->csvFileProcessor->setDelimiter($this->configuration->getDelimiter());
$CSVLines = $this->csvFileProcessor->processCSVFile();
// convert raw lines into arrays with individual ColumnValues
$valueArrays = $this->lineProcessor->processCSVLines($CSVLines);
// convert value arrays into (pseudo) transactions.
$pseudo = $this->columnValueConverter->processValueArrays($valueArrays);
// convert pseudo transactions into actual transactions.
$transactions = $this->pseudoTransactionProcessor->processPseudo($pseudo);
// save transactions to disk
die('TODO save to disk!');
$count = count($CSVLines);
$this->mergeMessages($count);
$this->mergeWarnings($count);
$this->mergeErrors($count);
}
/**
* @inheritDoc
*/
public function getIdentifier(): string
{
return $this->identifier;
}
/**
*
*/
private function generateIdentifier(): void
{
Log::debug('Going to generate conversion routine identifier.');
$disk = Storage::disk(self::DISK_NAME);
$count = 0;
do {
$generatedId = sprintf('conv-%s', Str::random(12));
$count++;
Log::debug(sprintf('Attempt #%d results in "%s"', $count, $generatedId));
} while ($count < 30 && $disk->exists($generatedId));
$this->identifier = $generatedId;
Log::info(sprintf('Job identifier is "%s"', $generatedId));
}
}

2
app/Services/Import/ImportJobStatus/ImportJobStatusManager.php

@ -145,7 +145,7 @@ class ImportJobStatusManager
*/
public static function setJobStatus(string $status): ImportJobStatus
{
$identifier = session()->get(Constants::CSV_CONVERSION_JOB_IDENTIFIER);
$identifier = session()->get(Constants::CONVERSION_JOB_IDENTIFIER);
Log::debug(sprintf('Now in setJobStatus(%s)', $status));
Log::debug(sprintf('Found "%s" in the session', $identifier));

1
app/Services/Import/ImportRoutineManager.php

@ -76,6 +76,7 @@ class ImportRoutineManager
*/
public function __construct(string $identifier = null)
{
die('i am deprecated');
Log::debug('Constructed ImportRoutineManager');
// get line converter

4
app/Services/Session/Constants.php

@ -57,8 +57,8 @@ class Constants
public const ROLES_COMPLETE_INDICATOR = 'role_config_complete';
public const MAPPING_COMPLETE_INDICATOR = 'mapping_config_complete';
// constants for CSV conversion job:
public const CSV_CONVERSION_JOB_IDENTIFIER = 'csv_c_job_id';
// constants for data conversion job:
public const CONVERSION_JOB_IDENTIFIER = 'conversion_job_id';
// /** @var string */

84
app/Services/Shared/Conversion/ConversionStatus.php

@ -0,0 +1,84 @@
<?php
/*
* ImportJobStatus.php
* Copyright (c) 2021 james@firefly-iii.org
*
* This file is part of the Firefly III Data Importer
* (https://github.com/firefly-iii/data-importer).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace App\Services\Shared\Conversion;
/**
* Class ConversionStatus
*/
class ConversionStatus
{
/** @var string */
public const CONVERSION_DONE = 'conv_done';
/** @var string */
public const CONVERSION_ERRORED = 'conv_errored';
/** @var string */
public const CONVERSION_RUNNING = 'conv_running';
/** @var string */
public const CONVERSION_WAITING = 'waiting_to_start';
public string $status;
public array $errors;
public array $warnings;
public array $messages;
/**
* ConversionStatus constructor.
*/
public function __construct()
{
$this->status = self::CONVERSION_WAITING;
$this->errors = [];
$this->warnings = [];
$this->messages = [];
}
/**
* @param array $array
*
* @return static
*/
public static function fromArray(array $array): self
{
$config = new self;
$config->status = $array['status'];
$config->errors = $array['errors'] ?? [];
$config->warnings = $array['warnings'] ?? [];
$config->messages = $array['messages'] ?? [];
return $config;
}
/**
* @return array
*/
public function toArray(): array
{
return [
'status' => $this->status,
'errors' => $this->errors,
'warnings' => $this->warnings,
'messages' => $this->messages,
];
}
}

47
app/Services/Shared/Conversion/RoutineManagerInterface.php

@ -0,0 +1,47 @@
<?php
/*
* RoutineManagerInterface.php
* Copyright (c) 2021 james@firefly-iii.org
*
* This file is part of the Firefly III Data Importer
* (https://github.com/firefly-iii/data-importer).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace App\Services\Shared\Conversion;
use App\Services\CSV\Configuration\Configuration;
/**
* Interface RoutineManagerInterface
*/
interface RoutineManagerInterface
{
/**
* @param Configuration $configuration
*/
public function setConfiguration(Configuration $configuration): void;
/**
*
*/
public function start(): void;
/**
* @return string
*/
public function getIdentifier(): string;
}

205
app/Services/Shared/Conversion/RoutineStatusManager.php

@ -0,0 +1,205 @@
<?php
/*
* RoutineStatusManager.php
* Copyright (c) 2021 james@firefly-iii.org
*
* This file is part of the Firefly III Data Importer
* (https://github.com/firefly-iii/data-importer).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace App\Services\Shared\Conversion;
use App\Exceptions\ImporterErrorException;
use App\Services\Session\Constants;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
use JsonException;
use Log;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Storage;
/**
* Class RoutineStatusManager
*/
class RoutineStatusManager
{
private const DISK_NAME = 'conversion-routines';
/**
* @param string $identifier
* @param int $index
* @param string $error
*/
public static function addError(string $identifier, int $index, string $error): void
{
$lineNo = $index + 1;
Log::debug(sprintf('Add error on index #%d (line no. %d): %s', $index, $lineNo, $error));
$disk = Storage::disk(self::DISK_NAME);
try {
if ($disk->exists($identifier)) {
try {
$status = ConversionStatus::fromArray(json_decode($disk->get($identifier), true, 512, JSON_THROW_ON_ERROR));
} catch (JsonException $e) {
Log::error($e->getMessage());
$status = new ConversionStatus;
}
$status->errors[$index] = $status->errors[$index] ?? [];
$status->errors[$index][] = $error;
self::storeConversionStatus($identifier, $status);
}
} catch (FileNotFoundException $e) {
Log::error($e->getMessage());
}
}
/**
* @param string $identifier
* @param ConversionStatus $status
*/
private static function storeConversionStatus(string $identifier, ConversionStatus $status): void
{
Log::debug(sprintf('Now in storeConversionStatus(%s): %s', $identifier, $status->status));
$disk = Storage::disk(self::DISK_NAME);
try {
$disk->put($identifier, json_encode($status->toArray(), JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT));
} catch (JsonException $e) {
// do nothing
Log::error($e->getMessage());
}
}
/**
* @param string $identifier
* @param int $index
* @param string $warning
*
*/
public static function addWarning(string $identifier, int $index, string $warning): void
{
$lineNo = $index + 1;
Log::debug(sprintf('Add warning on index #%d (line no. %d): %s', $index, $lineNo, $warning));
$disk = Storage::disk(self::DISK_NAME);
try {
if ($disk->exists($identifier)) {
try {
$status = ConversionStatus::fromArray(json_decode($disk->get($identifier), true, 512, JSON_THROW_ON_ERROR));
} catch (JsonException $e) {
Log::error($e->getMessage());
$status = new ConversionStatus;
}
$status->warnings[$index] = $status->warnings[$index] ?? [];
$status->warnings[$index][] = $warning;
self::storeConversionStatus($identifier, $status);
}
} catch (FileNotFoundException $e) {
Log::error($e->getMessage());
}
}
/**
* @param string $identifier
* @param int $index
* @param string $message
*
*/
public static function addMessage(string $identifier, int $index, string $message): void
{
$lineNo = $index + 1;
Log::debug(sprintf('Add message on index #%d (line no. %d): %s', $index, $lineNo, $message));
$disk = Storage::disk(self::DISK_NAME);
try {
if ($disk->exists($identifier)) {
try {
$status = ConversionStatus::fromArray(json_decode($disk->get($identifier), true, 512, JSON_THROW_ON_ERROR));
} catch (JsonException $e) {
Log::error($e->getMessage());
$status = new ConversionStatus;
}
$status->messages[$index] = $status->messages[$index] ?? [];
$status->messages[$index][] = $message;
self::storeConversionStatus($identifier, $status);
}
} catch (FileNotFoundException $e) {
Log::error($e->getMessage());
}
}
/**
* @param string $status
*
* @return ConversionStatus
* @throws ImporterErrorException
*/
public static function setConversionStatus(string $status): ConversionStatus
{
try {
$identifier = session()->get(Constants::CONVERSION_JOB_IDENTIFIER);
} catch (ContainerExceptionInterface|NotFoundExceptionInterface $e) {
throw new ImporterErrorException('No identifier found');
}
Log::debug(sprintf('Now in setConversionStatus(%s)', $status));
Log::debug(sprintf('Found "%s" in the session', $identifier));
$jobStatus = self::startOrFindConversion($identifier);
$jobStatus->status = $status;
self::storeConversionStatus($identifier, $jobStatus);
return $jobStatus;
}
/**
* @param string $identifier
*
* @return ConversionStatus
*/
public static function startOrFindConversion(string $identifier): ConversionStatus
{
Log::debug(sprintf('Now in startOrFindConversion(%s)', $identifier));
$disk = Storage::disk(self::DISK_NAME);
Log::debug(sprintf('Try to see if file exists for conversion "%s".', $identifier));
if ($disk->exists($identifier)) {
Log::debug(sprintf('Status file exists for conversion "%s".', $identifier));
try {
$array = json_decode($disk->get($identifier), true, 512, JSON_THROW_ON_ERROR);
$status = ConversionStatus::fromArray($array);
} catch (FileNotFoundException | JsonException $e) {
Log::error($e->getMessage());
$status = new ConversionStatus;
}
return $status;
}
Log::debug('File does not exist or error, create a new one.');
$status = new ConversionStatus;
try {
$disk->put($identifier, json_encode($status->toArray(), JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT));
} catch (JsonException $e) {
Log::error($e->getMessage());
}
Log::debug('Return status.', $status->toArray());
return $status;
}
}

4
config/filesystems.php

@ -77,6 +77,10 @@ return [
'driver' => 'local',
'root' => storage_path('jobs'),
],
'conversion-routines' => [
'driver' => 'local',
'root' => storage_path('conversion-routines'),
],
'configurations' => [
'driver' => 'local',
'root' => envNonEmpty('JSON_CONFIGURATION_DIR', storage_path('configurations')),

4
resources/views/index.twig

@ -96,7 +96,7 @@
Import from Nordigen (img)
</div>
<div class="card-body">
<p id="nordigen_result"><span class="fas fa-cog fa-spin"></span></p>
<p id="nordigen_result" style="display: none;"></p>
<button class="btn btn-info disabled" value="nordigen" name="flow" disabled="disabled" id="nordigen_button"><span class="fas fa-cog fa-spin"></span></button>
</div>
</div>
@ -107,7 +107,7 @@
Import from Spectre
</div>
<div class="card-body">
<p id="spectre_result"><span class="fas fa-cog fa-spin"></span></p>
<p id="spectre_result" style="display: none;"></p>
<button class="btn btn-info disabled" value="spectre" name="flow" disabled="disabled" id="spectre_button"><span class="fas fa-cog fa-spin"></span></button>
</div>
</div>

8
routes/web.php

@ -61,10 +61,10 @@ Route::post('/import/roles', ['uses' => 'Import\CSV\RoleController@postIndex', '
Route::get('/import/mapping', ['uses' => 'Import\CSV\MapController@index', 'as' => '006-mapping.index']);
Route::post('/import/mapping', ['uses' => 'Import\CSV\MapController@postIndex', 'as' => '006-mapping.post']);
// step 7: convert CSV to JSON transactions (CSV)
Route::get('/import/convert', ['uses' => 'Import\CSV\ConvertController@index', 'as' => '007-convert.index']);
Route::post('/import/convert/start', ['uses' => 'Import\CSV\ConvertController@start', 'as' => '007-convert.start']);
Route::get('/import/convert/status', ['uses' => 'Import\CSV\ConvertController@status', 'as' => '007-convert.status']);
// step 7: convert any import to JSON transactions
Route::get('/import/convert', ['uses' => 'Import\ConversionController@index', 'as' => '007-convert.index']);
Route::any('/import/convert/start', ['uses' => 'Import\ConversionController@start', 'as' => '007-convert.start']);
Route::get('/import/convert/status', ['uses' => 'Import\ConversionController@status', 'as' => '007-convert.status']);
// routes to go back to other steps (also takes care of session vars)

2
storage/conversion-routines/.gitignore

@ -0,0 +1,2 @@
*
!.gitignore
Loading…
Cancel
Save