diff --git a/app/Console/Commands/CreateImport.php b/app/Console/Commands/CreateImport.php index a4909328ed..209ed068cf 100644 --- a/app/Console/Commands/CreateImport.php +++ b/app/Console/Commands/CreateImport.php @@ -22,16 +22,14 @@ declare(strict_types=1); namespace FireflyIII\Console\Commands; -use Artisan; use FireflyIII\Exceptions\FireflyException; -use FireflyIII\Import\Logging\CommandHandler; use FireflyIII\Import\Routine\RoutineInterface; use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; use FireflyIII\Repositories\User\UserRepositoryInterface; +use FireflyIII\Services\Internal\File\EncryptService; use Illuminate\Console\Command; use Illuminate\Support\MessageBag; use Log; -use Monolog\Formatter\LineFormatter; use Preferences; /** @@ -61,46 +59,39 @@ class CreateImport extends Command {--token= : The user\'s access token.} {--start : Starts the job immediately.}'; - /** - * Create a new command instance. - */ - public function __construct() - { - parent::__construct(); - } - /** * Run the command. * - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) // cannot be helped - * @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's five exactly. + * @noinspection MultipleReturnStatementsInspection * * @throws FireflyException */ - public function handle() + public function handle(): int { if (!$this->verifyAccessToken()) { $this->errorLine('Invalid access token.'); - return; + return 1; } /** @var UserRepositoryInterface $userRepository */ $userRepository = app(UserRepositoryInterface::class); $file = $this->argument('file'); $configuration = $this->argument('configuration'); - $user = $userRepository->find(intval($this->option('user'))); + $user = $userRepository->findNull((int)$this->option('user')); $cwd = getcwd(); $type = strtolower($this->option('type')); if (!$this->validArguments()) { - return; + $this->errorLine('Invalid arguments.'); + + return 1; } $configurationData = json_decode(file_get_contents($configuration), true); if (null === $configurationData) { $this->errorLine(sprintf('Firefly III cannot read the contents of configuration file "%s" (working directory: "%s").', $configuration, $cwd)); - return; + return 1; } $this->infoLine(sprintf('Going to create a job to import file: %s', $file)); @@ -114,7 +105,10 @@ class CreateImport extends Command $job = $jobRepository->create($type); $this->infoLine(sprintf('Created job "%s"', $job->key)); - Artisan::call('firefly:encrypt-file', ['file' => $file, 'key' => $job->key]); + /** @var EncryptService $service */ + $service = app(EncryptService::class); + $service->encrypt($file, $job->key); + $this->infoLine('Stored import data...'); $jobRepository->setConfiguration($job, $configurationData); @@ -154,32 +148,45 @@ class CreateImport extends Command // clear cache for user: Preferences::setForUser($user, 'lastActivity', microtime()); - return; + return 0; + } + + /** + * @param string $message + * @param array|null $data + */ + private function errorLine(string $message, array $data = null): void + { + Log::error($message, $data ?? []); + $this->error($message); + + } + + /** + * @param string $message + * @param array $data + */ + private function infoLine(string $message, array $data = null): void + { + Log::info($message, $data ?? []); + $this->line($message); } /** * Verify user inserts correct arguments. * + * @noinspection MultipleReturnStatementsInspection * @return bool - * @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's five exactly. */ private function validArguments(): bool { - /** @var UserRepositoryInterface $userRepository */ - $userRepository = app(UserRepositoryInterface::class); - $file = $this->argument('file'); - $configuration = $this->argument('configuration'); - $user = $userRepository->find(intval($this->option('user'))); - $cwd = getcwd(); - $validTypes = config('import.options.file.import_formats'); - $type = strtolower($this->option('type')); - if (null === $user) { - $this->errorLine(sprintf('There is no user with ID %d.', $this->option('user'))); + $file = $this->argument('file'); + $configuration = $this->argument('configuration'); + $cwd = getcwd(); + $validTypes = config('import.options.file.import_formats'); + $type = strtolower($this->option('type')); - return false; - } - - if (!in_array($type, $validTypes)) { + if (!\in_array($type, $validTypes, true)) { $this->errorLine(sprintf('Cannot import file of type "%s"', $type)); return false; @@ -199,25 +206,4 @@ class CreateImport extends Command return true; } - - /** - * @param string $message - * @param array|null $data - */ - private function errorLine(string $message, array $data = null): void - { - Log::error($message, $data?? []); - $this->error($message); - - } - - /** - * @param string $message - * @param array $data - */ - private function infoLine(string $message, array $data = null): void - { - Log::info($message, $data?? []); - $this->line($message); - } } diff --git a/app/Console/Commands/EncryptFile.php b/app/Console/Commands/EncryptFile.php index b94cd1d981..0e787860e7 100644 --- a/app/Console/Commands/EncryptFile.php +++ b/app/Console/Commands/EncryptFile.php @@ -22,7 +22,8 @@ declare(strict_types=1); namespace FireflyIII\Console\Commands; -use Crypt; +use FireflyIII\Exceptions\FireflyException; +use FireflyIII\Services\Internal\File\EncryptService; use Illuminate\Console\Command; /** @@ -44,33 +45,26 @@ class EncryptFile extends Command */ protected $signature = 'firefly:encrypt-file {file} {key}'; - /** - * Create a new command instance. - */ - public function __construct() - { - parent::__construct(); - } - /** * Execute the console command. * * @throws \Illuminate\Contracts\Encryption\EncryptException */ - public function handle() + public function handle(): int { - $file = e(strval($this->argument('file'))); - if (!file_exists($file)) { - $this->error(sprintf('File "%s" does not seem to exist.', $file)); + $code = 0; + $file = (string)$this->argument('file'); + $key = (string)$this->argument('key'); + /** @var EncryptService $service */ + $service = app(EncryptService::class); - return; + try { + $service->encrypt($file, $key); + } catch (FireflyException $e) { + $this->error($e->getMessage()); + $code = 1; } - $content = file_get_contents($file); - $content = Crypt::encrypt($content); - $newName = e(strval($this->argument('key'))) . '.upload'; - $path = storage_path('upload') . '/' . $newName; - file_put_contents($path, $content); - $this->line(sprintf('Encrypted "%s" and put it in "%s"', $file, $path)); + return $code; } } diff --git a/app/Services/Internal/File/EncryptService.php b/app/Services/Internal/File/EncryptService.php new file mode 100644 index 0000000000..cd3b4eb6f7 --- /dev/null +++ b/app/Services/Internal/File/EncryptService.php @@ -0,0 +1,52 @@ +. + */ + +declare(strict_types=1); + +namespace FireflyIII\Services\Internal\File; + +use FireflyIII\Exceptions\FireflyException; + +/** + * Class EncryptService + */ +class EncryptService +{ + /** + * @param string $file + * @param string $key + * + * @throws FireflyException + */ + public function encrypt(string $file, string $key): void + { + if (!file_exists($file)) { + throw new FireflyException(sprintf('File "%s" does not seem to exist.', $file)); + } + $content = file_get_contents($file); + $content = Crypt::encrypt($content); + $newName = sprintf('%s.upload', $key); + $path = storage_path('upload') . '/' . $newName; + + file_put_contents($path, $content); + } + +} \ No newline at end of file diff --git a/tests/Unit/Console/Commands/CreateExportTest.php b/tests/Unit/Console/Commands/CreateExportTest.php index bc07ceb780..c14eb6d29f 100644 --- a/tests/Unit/Console/Commands/CreateExportTest.php +++ b/tests/Unit/Console/Commands/CreateExportTest.php @@ -81,8 +81,8 @@ class CreateExportTest extends TestCase $processor->shouldReceive('createZipFile')->once(); $fakeNews = 'I am a zipfile'; + Storage::fake('export'); Storage::disk('export')->put(sprintf('%s.zip', $job->key), $fakeNews); - $output = $this->artisan( 'firefly:create-export', [ diff --git a/tests/Unit/Console/Commands/CreateImportTest.php b/tests/Unit/Console/Commands/CreateImportTest.php new file mode 100644 index 0000000000..2f880d540c --- /dev/null +++ b/tests/Unit/Console/Commands/CreateImportTest.php @@ -0,0 +1,283 @@ +. + */ + +declare(strict_types=1); + +namespace Tests\Unit\Console\Commands; + + +use FireflyIII\Import\Routine\FileRoutine; +use FireflyIII\Models\ImportJob; +use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; +use FireflyIII\Repositories\User\UserRepositoryInterface; +use FireflyIII\Services\Internal\File\EncryptService; +use Illuminate\Support\Collection; +use Storage; +use Tests\TestCase; + + +/** + * Class CreateImportTest + */ +class CreateImportTest extends TestCase +{ + /** + * @covers \FireflyIII\Console\Commands\CreateImport + * @covers \FireflyIII\Console\Commands\EncryptFile + * @covers \FireflyIII\Console\Commands\VerifiesAccessToken + */ + public function testBasic() + { + $jobRepos = $this->mock(ImportJobRepositoryInterface::class); + $userRepos = $this->mock(UserRepositoryInterface::class); + $encrypter = $this->mock(EncryptService::class); + $routine = $this->mock(FileRoutine::class); + + $collection = new Collection(); + $collection->push('I am error'); + + $job = new ImportJob; + $job->key = 'import-' . random_int(1, 1000); + $job->file_type = 'csv'; + $job->user = $this->user(); + + $userRepos->shouldReceive('findNull')->andReturn($this->user())->times(2); + $jobRepos->shouldReceive('setUser')->once(); + $jobRepos->shouldReceive('create')->once()->andReturn($job); + $jobRepos->shouldReceive('setConfiguration')->once(); + $jobRepos->shouldReceive('updateStatus')->once(); + $encrypter->shouldReceive('encrypt')->once(); + $routine->shouldReceive('setJob')->once(); + $routine->shouldReceive('run')->once(); + $routine->shouldReceive('getErrors')->once()->andReturn($collection); + $routine->shouldReceive('getJournals')->once()->andReturn(new Collection()); + $routine->shouldReceive('getLines')->once()->andReturn(7); + + Storage::fake('upload'); + + $output = $this->artisan( + 'firefly:create-import', + [ + '--user' => 1, + '--token' => 'token', + 'file' => 'storage/build/test-upload.csv', + 'configuration' => 'storage/build/test-upload.json', + '--start' => true, + + ] + ); + + $this->assertEquals(0, $output); + } + + /** + * @covers \FireflyIII\Console\Commands\CreateImport + * @covers \FireflyIII\Console\Commands\EncryptFile + * @covers \FireflyIII\Console\Commands\VerifiesAccessToken + */ + public function testInvalidToken() + { + $jobRepos = $this->mock(ImportJobRepositoryInterface::class); + $userRepos = $this->mock(UserRepositoryInterface::class); + $encrypter = $this->mock(EncryptService::class); + $routine = $this->mock(FileRoutine::class); + + $collection = new Collection(); + $collection->push('I am error'); + + $job = new ImportJob; + $job->key = 'import-' . random_int(1, 1000); + $job->file_type = 'csv'; + $job->user = $this->user(); + + $userRepos->shouldReceive('findNull')->andReturn($this->user())->times(1); + + Storage::fake('upload'); + + $output = $this->artisan( + 'firefly:create-import', + [ + '--user' => 1, + '--token' => 'tokenX', + 'file' => 'storage/build/test-upload.csv', + 'configuration' => 'storage/build/test-upload.json', + '--start' => true, + + ] + ); + + $this->assertEquals(1, $output); + } + + /** + * @covers \FireflyIII\Console\Commands\CreateImport + * @covers \FireflyIII\Console\Commands\EncryptFile + * @covers \FireflyIII\Console\Commands\VerifiesAccessToken + */ + public function testInvalidType() + { + $jobRepos = $this->mock(ImportJobRepositoryInterface::class); + $userRepos = $this->mock(UserRepositoryInterface::class); + $encrypter = $this->mock(EncryptService::class); + $routine = $this->mock(FileRoutine::class); + + $collection = new Collection(); + $collection->push('I am error'); + + $job = new ImportJob; + $job->key = 'import-' . random_int(1, 1000); + $job->file_type = 'csv'; + $job->user = $this->user(); + + $userRepos->shouldReceive('findNull')->andReturn($this->user())->times(2); + + $output = $this->artisan( + 'firefly:create-import', + [ + '--user' => 1, + '--token' => 'token', + '--type' => 'csvX', + 'file' => 'storage/build/test-upload.csv', + 'configuration' => 'storage/build/test-upload.json', + '--start' => true, + + ] + ); + + $this->assertEquals(1, $output); + } + + + /** + * @covers \FireflyIII\Console\Commands\CreateImport + * @covers \FireflyIII\Console\Commands\EncryptFile + * @covers \FireflyIII\Console\Commands\VerifiesAccessToken + */ + public function testInvalidJSON() + { + $jobRepos = $this->mock(ImportJobRepositoryInterface::class); + $userRepos = $this->mock(UserRepositoryInterface::class); + $encrypter = $this->mock(EncryptService::class); + $routine = $this->mock(FileRoutine::class); + + $collection = new Collection(); + $collection->push('I am error'); + + $job = new ImportJob; + $job->key = 'import-' . random_int(1, 1000); + $job->file_type = 'csv'; + $job->user = $this->user(); + + $userRepos->shouldReceive('findNull')->andReturn($this->user())->times(2); + + $output = $this->artisan( + 'firefly:create-import', + [ + '--user' => 1, + '--token' => 'token', + '--type' => 'csv', + 'file' => 'storage/build/test-upload.csv', + 'configuration' => 'storage/build/test-upload.csv', + '--start' => true, + + ] + ); + + $this->assertEquals(1, $output); + } + + /** + * @covers \FireflyIII\Console\Commands\CreateImport + * @covers \FireflyIII\Console\Commands\EncryptFile + * @covers \FireflyIII\Console\Commands\VerifiesAccessToken + */ + public function testFileNotFound() + { + $jobRepos = $this->mock(ImportJobRepositoryInterface::class); + $userRepos = $this->mock(UserRepositoryInterface::class); + $encrypter = $this->mock(EncryptService::class); + $routine = $this->mock(FileRoutine::class); + + $collection = new Collection(); + $collection->push('I am error'); + + $job = new ImportJob; + $job->key = 'import-' . random_int(1, 1000); + $job->file_type = 'csv'; + $job->user = $this->user(); + + $userRepos->shouldReceive('findNull')->andReturn($this->user())->times(2); + + $output = $this->artisan( + 'firefly:create-import', + [ + '--user' => 1, + '--token' => 'token', + '--type' => 'csv', + 'file' => 'storage/build/test-uploadX.csv', + 'configuration' => 'storage/build/test-upload.json', + '--start' => true, + + ] + ); + + $this->assertEquals(1, $output); + } + + /** + * @covers \FireflyIII\Console\Commands\CreateImport + * @covers \FireflyIII\Console\Commands\EncryptFile + * @covers \FireflyIII\Console\Commands\VerifiesAccessToken + */ + public function testConfigNotFound() + { + $jobRepos = $this->mock(ImportJobRepositoryInterface::class); + $userRepos = $this->mock(UserRepositoryInterface::class); + $encrypter = $this->mock(EncryptService::class); + $routine = $this->mock(FileRoutine::class); + + $collection = new Collection(); + $collection->push('I am error'); + + $job = new ImportJob; + $job->key = 'import-' . random_int(1, 1000); + $job->file_type = 'csv'; + $job->user = $this->user(); + + $userRepos->shouldReceive('findNull')->andReturn($this->user())->times(2); + + $output = $this->artisan( + 'firefly:create-import', + [ + '--user' => 1, + '--token' => 'token', + '--type' => 'csv', + 'file' => 'storage/build/test-upload.csv', + 'configuration' => 'storage/build/test-uploadX.json', + '--start' => true, + + ] + ); + + $this->assertEquals(1, $output); + } + +} \ No newline at end of file