Merge branch 'develop' into feature/rules-on-existing-transactions

This commit is contained in:
Robert Horlings
2016-02-23 13:17:07 +01:00
50 changed files with 408 additions and 239 deletions

View File

@@ -11,13 +11,15 @@ declare(strict_types = 1);
namespace FireflyIII\Export\Collector;
use Amount;
use Auth;
use Crypt;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\ExportJob;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Support\Collection;
use Log;
use Storage;
/**
* Class AttachmentCollector
@@ -28,6 +30,12 @@ class AttachmentCollector extends BasicCollector implements CollectorInterface
{
/** @var string */
private $explanationString = '';
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
private $exportDisk;
/** @var AttachmentRepositoryInterface */
private $repository;
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
private $uploadDisk;
/**
* AttachmentCollector constructor.
@@ -36,6 +44,11 @@ class AttachmentCollector extends BasicCollector implements CollectorInterface
*/
public function __construct(ExportJob $job)
{
$this->repository = app('FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface');
// make storage:
$this->uploadDisk = Storage::disk('upload');
$this->exportDisk = Storage::disk('export');
parent::__construct($job);
}
@@ -45,35 +58,18 @@ class AttachmentCollector extends BasicCollector implements CollectorInterface
public function run()
{
// grab all the users attachments:
$attachments = Auth::user()->attachments()->get();
Log::debug('Found ' . $attachments->count() . ' attachments.');
$attachments = $this->getAttachments();
/** @var Attachment $attachment */
foreach ($attachments as $attachment) {
$originalFile = storage_path('upload') . DIRECTORY_SEPARATOR . 'at-' . $attachment->id . '.data';
if (file_exists($originalFile)) {
Log::debug('Stored 1 attachment');
try {
$decrypted = Crypt::decrypt(file_get_contents($originalFile));
$newFile = storage_path('export') . DIRECTORY_SEPARATOR . $this->job->key . '-Attachment nr. ' . $attachment->id . ' - '
. $attachment->filename;
file_put_contents($newFile, $decrypted);
$this->getFiles()->push($newFile);
// explain:
$this->explain($attachment);
} catch (DecryptException $e) {
Log::error('Catchable error: could not decrypt attachment #' . $attachment->id);
}
}
$this->exportAttachment($attachment);
}
// put the explanation string in a file and attach it as well.
$explanationFile = storage_path('export') . DIRECTORY_SEPARATOR . $this->job->key . '-Source of all your attachments explained.txt';
file_put_contents($explanationFile, $this->explanationString);
$this->getFiles()->push($explanationFile);
$file = $this->job->key . '-Source of all your attachments explained.txt';
$this->exportDisk->put($file, $this->explanationString);
Log::debug('Also put explanation file "' . $file . '" in the zip.');
$this->getFiles()->push($file);
}
/**
@@ -96,4 +92,57 @@ class AttachmentCollector extends BasicCollector implements CollectorInterface
$this->explanationString .= $string;
}
/**
* @param Attachment $attachment
*
* @return bool
*/
private function exportAttachment(Attachment $attachment): bool
{
$file = $attachment->fileName();
Log::debug('Original file is at "' . $file . '".');
if ($this->uploadDisk->exists($file)) {
try {
$decrypted = Crypt::decrypt($this->uploadDisk->get($file));
$exportFile = $this->exportFileName($attachment);
$this->exportDisk->put($exportFile, $decrypted);
$this->getFiles()->push($exportFile);
Log::debug('Stored file content in new file "' . $exportFile . '", which will be in the final zip file.');
// explain:
$this->explain($attachment);
} catch (DecryptException $e) {
Log::error('Catchable error: could not decrypt attachment #' . $attachment->id . ' because: ' . $e->getMessage());
}
}
return true;
}
/**
* Returns the new file name for the export file.
*
* @param $attachment
*
* @return string
*/
private function exportFileName($attachment): string
{
return sprintf('%s-Attachment nr. %s - %s', $this->job->key, strval($attachment->id), $attachment->filename);
}
/**
* @return Collection
*/
private function getAttachments(): Collection
{
$attachments = $this->repository->get();
Log::debug('Found ' . $attachments->count() . ' attachments.');
return $attachments;
}
}

View File

@@ -15,6 +15,8 @@ use Crypt;
use FireflyIII\Models\ExportJob;
use Illuminate\Contracts\Encryption\DecryptException;
use Log;
use Storage;
/**
* Class UploadCollector
*
@@ -22,6 +24,12 @@ use Log;
*/
class UploadCollector extends BasicCollector implements CollectorInterface
{
/** @var string */
private $expected;
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
private $exportDisk;
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
private $uploadDisk;
/**
* AttachmentCollector constructor.
@@ -31,6 +39,11 @@ class UploadCollector extends BasicCollector implements CollectorInterface
public function __construct(ExportJob $job)
{
parent::__construct($job);
// make storage:
$this->uploadDisk = Storage::disk('upload');
$this->exportDisk = Storage::disk('export');
$this->expected = 'csv-upload-' . Auth::user()->id . '-';
}
/**
@@ -39,31 +52,68 @@ class UploadCollector extends BasicCollector implements CollectorInterface
public function run()
{
// grab upload directory.
$path = storage_path('upload');
$files = scandir($path);
// only allow old uploads for this user:
$expected = 'csv-upload-' . Auth::user()->id . '-';
$len = strlen($expected);
$files = $this->uploadDisk->files();
Log::debug('Found ' . count($files) . ' files in the upload directory.');
foreach ($files as $entry) {
if (substr($entry, 0, $len) === $expected) {
try {
// this is an original upload.
$parts = explode('-', str_replace(['.csv.encrypted', $expected], '', $entry));
$originalUpload = intval($parts[1]);
$date = date('Y-m-d \a\t H-i-s', $originalUpload);
$newFileName = 'Old CSV import dated ' . $date . '.csv';
$content = Crypt::decrypt(file_get_contents($path . DIRECTORY_SEPARATOR . $entry));
$fullPath = storage_path('export') . DIRECTORY_SEPARATOR . $this->job->key . '-' . $newFileName;
$this->processOldUpload($entry);
}
}
// write to file:
file_put_contents($fullPath, $content);
/**
* @param string $entry
*
* @return string
*/
private function getOriginalUploadDate(string $entry): string
{
// this is an original upload.
$parts = explode('-', str_replace(['.csv.encrypted', $this->expected], '', $entry));
$originalUpload = intval($parts[1]);
$date = date('Y-m-d \a\t H-i-s', $originalUpload);
// add entry to set:
$this->getFiles()->push($fullPath);
} catch (DecryptException $e) {
Log::error('Could not decrypt old CSV import file ' . $entry . '. Skipped.');
}
return $date;
}
/**
* @param string $entry
*
* @return bool
*/
private function isValidFile(string $entry): bool
{
$len = strlen($this->expected);
if (substr($entry, 0, $len) === $this->expected) {
Log::debug($entry . ' is part of this users original uploads.');
return true;
}
Log::debug($entry . ' is not part of this users original uploads.');
return false;
}
/**
* @param $entry
*/
private function processOldUpload(string $entry)
{
$content = '';
if ($this->isValidFile($entry)) {
try {
$content = Crypt::decrypt($this->uploadDisk->get($entry));
} catch (DecryptException $e) {
Log::error('Could not decrypt old CSV import file ' . $entry . '. Skipped because ' . $e->getMessage());
}
}
if (strlen($content) > 0) {
// continue with file:
$date = $this->getOriginalUploadDate($entry);
$file = $this->job->key . '-Old CSV import dated ' . $date . '.csv';
Log::debug('Will put "' . $file . '" in the zip file.');
$this->exportDisk->put($file, $content);
$this->getFiles()->push($file);
}
}
}

View File

@@ -11,6 +11,8 @@ declare(strict_types = 1);
namespace FireflyIII\Export;
use FireflyIII\Models\ExportJob;
use Log;
use Storage;
/**
* Class ConfigurationFile
@@ -19,6 +21,8 @@ use FireflyIII\Models\ExportJob;
*/
class ConfigurationFile
{
/** @var \Illuminate\Contracts\Filesystem\Filesystem */
private $exportDisk;
/** @var ExportJob */
private $job;
@@ -29,7 +33,8 @@ class ConfigurationFile
*/
public function __construct(ExportJob $job)
{
$this->job = $job;
$this->job = $job;
$this->exportDisk = Storage::disk('export');
}
/**
@@ -51,9 +56,10 @@ class ConfigurationFile
foreach ($fields as $field) {
$configuration['roles'][] = $types[$field];
}
$file = storage_path('export') . DIRECTORY_SEPARATOR . $this->job->key . '-configuration.json';
file_put_contents($file, json_encode($configuration, JSON_PRETTY_PRINT));
$file = $this->job->key . '-configuration.json';
Log::debug('Created JSON config file.');
Log::debug('Will put "' . $file . '" in the ZIP file.');
$this->exportDisk->put($file, json_encode($configuration, JSON_PRETTY_PRINT));
return $file;
}

View File

@@ -14,6 +14,7 @@ use FireflyIII\Export\Entry;
use FireflyIII\Models\ExportJob;
use League\Csv\Writer;
use SplFileObject;
use Storage;
/**
* Class CsvExporter
@@ -25,9 +26,6 @@ class CsvExporter extends BasicExporter implements ExporterInterface
/** @var string */
private $fileName;
/** @var resource */
private $handler;
/**
* CsvExporter constructor.
*
@@ -36,6 +34,7 @@ class CsvExporter extends BasicExporter implements ExporterInterface
public function __construct(ExportJob $job)
{
parent::__construct($job);
}
/**
@@ -54,9 +53,11 @@ class CsvExporter extends BasicExporter implements ExporterInterface
// create temporary file:
$this->tempFile();
// necessary for CSV writer:
$fullPath = storage_path('export') . DIRECTORY_SEPARATOR . $this->fileName;
// create CSV writer:
$writer = Writer::createFromPath(new SplFileObject($this->fileName, 'a+'), 'w');
//the $writer object open mode will be 'w'!!
$writer = Writer::createFromPath(new SplFileObject($fullPath, 'a+'), 'w');
// all rows:
$rows = [];
@@ -76,8 +77,6 @@ class CsvExporter extends BasicExporter implements ExporterInterface
private function tempFile()
{
$fileName = $this->job->key . '-records.csv';
$this->fileName = storage_path('export') . DIRECTORY_SEPARATOR . $fileName;
$this->handler = fopen($this->fileName, 'w');
$this->fileName = $this->job->key . '-records.csv';
}
}

View File

@@ -16,6 +16,8 @@ use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\ExportJob;
use FireflyIII\Models\TransactionJournal;
use Illuminate\Support\Collection;
use Log;
use Storage;
use ZipArchive;
/**
@@ -88,6 +90,13 @@ class Processor
$args = [$this->accounts, Auth::user(), $this->settings['startDate'], $this->settings['endDate']];
$journalCollector = app('FireflyIII\Repositories\Journal\JournalCollector', $args);
$this->journals = $journalCollector->collect();
Log::debug(
'Collected ' .
$this->journals->count() . ' journals (between ' .
$this->settings['startDate']->format('Y-m-d') . ' and ' .
$this->settings['endDate']->format('Y-m-d')
. ').'
);
}
public function collectOldUploads()
@@ -103,10 +112,13 @@ class Processor
*/
public function convertJournals()
{
$count = 0;
/** @var TransactionJournal $journal */
foreach ($this->journals as $journal) {
$this->exportEntries->push(Entry::fromJournal($journal));
$count++;
}
Log::debug('Converted ' . $count . ' journals to "Entry" objects.');
}
public function createConfigFile()
@@ -118,24 +130,32 @@ class Processor
public function createZipFile()
{
$zip = new ZipArchive;
$filename = storage_path('export') . DIRECTORY_SEPARATOR . $this->job->key . '.zip';
$file = $this->job->key . '.zip';
$fullPath = storage_path('export') . '/' . $file;
Log::debug('Will create zip file at ' . $fullPath);
if ($zip->open($filename, ZipArchive::CREATE) !== true) {
if ($zip->open($fullPath, ZipArchive::CREATE) !== true) {
throw new FireflyException('Cannot store zip file.');
}
// for each file in the collection, add it to the zip file.
$search = storage_path('export') . DIRECTORY_SEPARATOR . $this->job->key . '-';
/** @var string $file */
foreach ($this->getFiles() as $file) {
$zipName = str_replace($search, '', $file);
$zip->addFile($file, $zipName);
$disk = Storage::disk('export');
foreach ($this->getFiles() as $entry) {
// is part of this job?
$zipFileName = str_replace($this->job->key . '-', '', $entry);
$result = $zip->addFromString($zipFileName, $disk->get($entry));
if (!$result) {
Log::error('Could not add "' . $entry . '" into zip file as "' . $zipFileName . '".');
}
}
$zip->close();
// delete the files:
foreach ($this->getFiles() as $file) {
unlink($file);
Log::debug('Will now delete file "' . $file . '".');
$disk->delete($file);
}
Log::debug('Done!');
}
/**
@@ -145,9 +165,11 @@ class Processor
{
$exporterClass = Config::get('firefly.export_formats.' . $this->exportFormat);
$exporter = app($exporterClass, [$this->job]);
Log::debug('Going to export ' . $this->exportEntries->count() . ' export entries into ' . $this->exportFormat . ' format.');
$exporter->setEntries($this->exportEntries);
$exporter->run();
$this->files->push($exporter->getFileName());
Log::debug('Added "' . $exporter->getFileName() . '" to the list of files to include in the zip.');
}
/**