diff --git a/app/Http/Controllers/ImportController.php b/app/Http/Controllers/ImportController.php index 0319bdb87f..45524c1714 100644 --- a/app/Http/Controllers/ImportController.php +++ b/app/Http/Controllers/ImportController.php @@ -2,7 +2,14 @@ namespace FireflyIII\Http\Controllers; +use Crypt; use FireflyIII\Http\Requests; +use FireflyIII\Http\Requests\ImportUploadRequest; +use FireflyIII\Import\Importer\ImporterInterface; +use FireflyIII\Models\ImportJob; +use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface; +use SplFileObject; +use Storage; use View; /** @@ -22,6 +29,26 @@ class ImportController extends Controller View::share('title', trans('firefly.import_data')); } + /** + * @param ImportJob $job + * + * @return View + */ + public function configure(ImportJob $job) + { + // create proper importer (depends on job) + $type = $job->file_type; + /** @var ImporterInterface $importer */ + $importer = app('FireflyIII\Import\Importer\\' . ucfirst($type) . 'Importer'); + $importer->setJob($job); + $importer->configure(); + $data = $importer->getConfigurationData(); + + return view('import.' . $type . '.configure', compact('data', 'job')); + + + } + /** * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ @@ -38,4 +65,27 @@ class ImportController extends Controller return view('import.index', compact('subTitle', 'subTitleIcon', 'importFileTypes', 'defaultImportType')); } + + /** + * @param ImportUploadRequest $request + * @param ImportJobRepositoryInterface $repository + * + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector + */ + public function upload(ImportUploadRequest $request, ImportJobRepositoryInterface $repository) + { + // create import job: + $type = $request->get('import_file_type'); + $job = $repository->create($type); + $upload = $request->files->get('import_file'); + $newName = $job->key . '.upload'; + $uploaded = new SplFileObject($upload->getRealPath()); + $content = $uploaded->fread($uploaded->getSize()); + $contentEncrypted = Crypt::encrypt($content); + $disk = Storage::disk('upload'); + $disk->put($newName, $contentEncrypted); + + return redirect(route('import.configure', [$job->key])); + + } } diff --git a/app/Http/Requests/ImportUploadRequest.php b/app/Http/Requests/ImportUploadRequest.php new file mode 100644 index 0000000000..0f1e39155b --- /dev/null +++ b/app/Http/Requests/ImportUploadRequest.php @@ -0,0 +1,46 @@ + 'required|file', + 'import_file_type' => 'required|in:' . join(',', $types), + ]; + + } +} diff --git a/app/Http/routes.php b/app/Http/routes.php index 43b7577f3f..abf3bbcd17 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -223,8 +223,9 @@ Route::group( /** * IMPORT CONTROLLER */ - Route::get('/import', ['uses' => 'ImportController@index', 'as' => 'import.index']); - Route::post('/import/upload', ['uses' => 'ImportController@upload', 'as' => 'import.upload']); + Route::get('/import', ['uses' => 'ImportController@index','as' => 'import.index']); + Route::post('/import/upload', ['uses' => 'ImportController@upload','as' => 'import.upload']); + Route::get('/import/configure/{importJob}', ['uses' => 'ImportController@configure','as' => 'import.configure']); /** * Help Controller diff --git a/app/Import/Importer/CsvImporter.php b/app/Import/Importer/CsvImporter.php new file mode 100644 index 0000000000..801c61f0ee --- /dev/null +++ b/app/Import/Importer/CsvImporter.php @@ -0,0 +1,81 @@ +getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]); + $delimiters = [ + ',' => trans('form.csv_comma'), + ';' => trans('form.csv_semicolon'), + 'tab' => trans('form.csv_tab'), + ]; + + $data = [ + 'accounts' => ExpandedForm::makeSelectList($accounts), + 'specifix' => [], + 'delimiters' => $delimiters, + ]; + + return $data; + } + + /** + * @param ImportJob $job + */ + public function setJob(ImportJob $job) + { + $this->job = $job; + } + + /** + * Returns a Map thing used to allow the user to + * define roles for each entry. + * + * @return Map + */ + public function prepareRoles(): Map + { + return 'do not work'; + exit; + } +} \ No newline at end of file diff --git a/app/Import/Importer/ImporterInterface.php b/app/Import/Importer/ImporterInterface.php new file mode 100644 index 0000000000..4df74f85ba --- /dev/null +++ b/app/Import/Importer/ImporterInterface.php @@ -0,0 +1,52 @@ +where('user_id', Auth::user()->id)->first(); + if (!is_null($model)) { + return $model; + } + } + throw new NotFoundHttpException; + } + + /** + * @param $status + */ + public function change($status) + { + $this->status = $status; + $this->save(); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function user() + { + return $this->belongsTo('FireflyIII\User'); + } +} diff --git a/app/Providers/ExportJobServiceProvider.php b/app/Providers/ExportJobServiceProvider.php index 380b14a2e9..f39e24cd1e 100644 --- a/app/Providers/ExportJobServiceProvider.php +++ b/app/Providers/ExportJobServiceProvider.php @@ -31,6 +31,27 @@ class ExportJobServiceProvider extends ServiceProvider */ public function boot() { + $this->exportJob(); + $this->importJob(); + + } + + /** + * Register the application services. + * + * @return void + */ + public function register() + { + // + } + + /** + * + */ + private function exportJob() + { + $this->app->bind( 'FireflyIII\Repositories\ExportJob\ExportJobRepositoryInterface', function (Application $app, array $arguments) { @@ -46,13 +67,20 @@ class ExportJobServiceProvider extends ServiceProvider ); } - /** - * Register the application services. - * - * @return void - */ - public function register() + private function importJob() { - // + $this->app->bind( + 'FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface', + function (Application $app, array $arguments) { + if (!isset($arguments[0]) && $app->auth->check()) { + return app('FireflyIII\Repositories\ImportJob\ImportJobRepository', [$app->auth->user()]); + } + if (!isset($arguments[0]) && !$app->auth->check()) { + throw new FireflyException('There is no user present.'); + } + + return app('FireflyIII\Repositories\ImportJob\ImportJobRepository', $arguments); + } + ); } } diff --git a/app/Repositories/ImportJob/ImportJobRepository.php b/app/Repositories/ImportJob/ImportJobRepository.php new file mode 100644 index 0000000000..4e281d83c6 --- /dev/null +++ b/app/Repositories/ImportJob/ImportJobRepository.php @@ -0,0 +1,81 @@ +user = $user; + } + + /** + * @param string $fileType + * + * @return ImportJob + */ + public function create(string $fileType): ImportJob + { + $count = 0; + while ($count < 30) { + $key = Str::random(12); + $existing = $this->findByKey($key); + if (is_null($existing->id)) { + $importJob = new ImportJob; + $importJob->user()->associate($this->user); + $importJob->file_type = $fileType; + $importJob->key = Str::random(12); + $importJob->status = 'import_status_never_started'; + $importJob->save(); + + // breaks the loop: + return $importJob; + } + $count++; + + } + + return new ImportJob; + } + + /** + * @param string $key + * + * @return ImportJob + */ + public function findByKey(string $key): ImportJob + { + $result = $this->user->importJobs()->where('key', $key)->first(); + if (is_null($result)) { + return new ImportJob; + } + + return $result; + } +} \ No newline at end of file diff --git a/app/Repositories/ImportJob/ImportJobRepositoryInterface.php b/app/Repositories/ImportJob/ImportJobRepositoryInterface.php new file mode 100644 index 0000000000..24cdd2aca9 --- /dev/null +++ b/app/Repositories/ImportJob/ImportJobRepositoryInterface.php @@ -0,0 +1,36 @@ +hasMany('FireflyIII\Models\ExportJob'); } + /** + * @return HasMany + */ + public function importjobs(): HasMany + { + return $this->hasMany('FireflyIII\Models\ImportJob'); + } + /** * Checks if the user has a role by its name. * diff --git a/config/app.php b/config/app.php index 79a9e67ed6..731400f5b1 100644 --- a/config/app.php +++ b/config/app.php @@ -180,8 +180,8 @@ return [ // own stuff: -// Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class, -// Barryvdh\Debugbar\ServiceProvider::class, + Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class, + Barryvdh\Debugbar\ServiceProvider::class, 'DaveJamesMiller\Breadcrumbs\ServiceProvider', 'TwigBridge\ServiceProvider', 'PragmaRX\Google2FA\Vendor\Laravel\ServiceProvider', diff --git a/config/firefly.php b/config/firefly.php index 78a1b62634..e19fd5d75b 100644 --- a/config/firefly.php +++ b/config/firefly.php @@ -126,6 +126,7 @@ return [ 'rule' => 'FireflyIII\Models\Rule', 'ruleGroup' => 'FireflyIII\Models\RuleGroup', 'jobKey' => 'FireflyIII\Models\ExportJob', + 'importJob' => 'FireflyIII\Models\ImportJob', // lists 'accountList' => 'FireflyIII\Support\Binder\AccountList', 'budgetList' => 'FireflyIII\Support\Binder\BudgetList', diff --git a/database/migrations/2016_05_23_173524_changes_for_v391.php b/database/migrations/2016_05_23_173524_changes_for_v391.php new file mode 100644 index 0000000000..b8efd50b4d --- /dev/null +++ b/database/migrations/2016_05_23_173524_changes_for_v391.php @@ -0,0 +1,44 @@ +increments('id'); + $table->timestamps(); + $table->integer('user_id')->unsigned(); + $table->string('key', 12)->unique(); + $table->string('file_type', 12); + $table->string('status', 45); + + // connect rule groups to users + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + + } + ); + } +} diff --git a/resources/lang/en_US/firefly.php b/resources/lang/en_US/firefly.php index 6d3f31f8b0..61ed2cd803 100644 --- a/resources/lang/en_US/firefly.php +++ b/resources/lang/en_US/firefly.php @@ -326,97 +326,12 @@ return [ 'title_transfer' => 'Transfers', 'title_transfers' => 'Transfers', - - // csv import: - 'csv_import' => 'Import CSV file', - 'csv' => 'CSV', - 'csv_index_title' => 'Upload and import a CSV file', - 'csv_define_column_roles' => 'Define column roles', - 'csv_map_values' => 'Map found values to existing values', - 'csv_download_config' => 'Download CSV configuration file.', - 'csv_index_text' => 'This form allows you to import a CSV file with transactions into Firefly. It is based on the excellent CSV importer made by the folks at Atlassian. Simply upload your CSV file and follow the instructions. If you would like to learn more, please click on the button at the top of this page.', - 'csv_index_beta_warning' => 'This tool is very much in beta. Please proceed with caution', - 'csv_header_help' => 'Check this box when your CSV file\'s first row consists of column names, not actual data', - 'csv_date_help' => 'Date time format in your CSV. Follow the format like this page indicates. The default value will parse dates that look like this: :dateExample.', - 'csv_csv_file_help' => 'Select the CSV file here. You can only upload one file at a time', - 'csv_csv_config_file_help' => 'Select your CSV import configuration here. If you do not know what this is, ignore it. It will be explained later.', - 'csv_upload_button' => 'Start importing CSV', - 'csv_column_roles_title' => 'Define column roles', - 'csv_column_roles_text' => 'Firefly does not know what each column means. You need to indicate what every column is. Please check out the example data if you\'re not sure yourself. Click on the question mark (top right of the page) to learn what each column means. If you want to map imported data onto existing data in Firefly, use the checkbox. The next step will show you what this button does.', - 'csv_column_roles_table' => 'Column roles', - 'csv_column' => 'CSV column', - 'csv_column_name' => 'CSV column name', - 'csv_column_example' => 'Column example data', - 'csv_column_role' => 'Column contains?', - 'csv_do_map_value' => 'Map value?', - 'csv_continue' => 'Continue to the next step', - 'csv_go_back' => 'Go back to the previous step', - 'csv_map_title' => 'Map found values to existing values', - 'csv_map_text' => 'This page allows you to map the values from the CSV file to existing entries in your database. This ensures that accounts and other things won\'t be created twice.', - 'csv_field_value' => 'Field value from CSV', - 'csv_field_mapped_to' => 'Must be mapped to...', - 'csv_do_not_map' => 'Do not map this value', - 'csv_download_config_title' => 'Download CSV configuration', - 'csv_download_config_text' => 'Everything you\'ve just set up can be downloaded as a configuration file. Click the button to do so.', - 'csv_more_information_text' => 'If the import fails, you can use this configuration file so you don\'t have to start all over again. But, if the import succeeds, it will be easier to upload similar CSV files.', - 'csv_do_download_config' => 'Download configuration file.', - 'csv_empty_description' => '(empty description)', - 'csv_upload_form' => 'CSV upload form', - 'csv_index_unsupported_warning' => 'The CSV importer is yet incapable of doing the following:', - 'csv_unsupported_map' => 'The importer cannot map the column ":columnRole" to existing values in the database.', - 'csv_unsupported_value' => 'The importer does not know how to handle values in columns marked as ":columnRole".', - 'csv_cannot_store_value' => 'The importer has not reserved space for columns marked ":columnRole" and will be incapable of processing them.', - 'csv_process_title' => 'CSV import finished!', - 'csv_process_text' => 'The CSV importer has finished and has processed :rows rows', - 'csv_row' => 'Row', - 'csv_import_with_errors' => 'There was one error.|There were :errors errors.', - 'csv_error_see_logs' => 'Check the log files to see details.', - 'csv_process_new_entries' => 'Firefly has created :imported new transaction(s).', - 'csv_start_over' => 'Import again', - 'csv_to_index' => 'Back home', - 'csv_upload_not_writeable' => 'Cannot write to the path mentioned here. Cannot upload', - 'csv_column__ignore' => '(ignore this column)', - 'csv_column_account-iban' => 'Asset account (IBAN)', - 'csv_column_account-id' => 'Asset account ID (matching Firefly)', - 'csv_column_account-name' => 'Asset account (name)', - 'csv_column_amount' => 'Amount', - 'csv_column_amount-comma-separated' => 'Amount (comma as decimal separator)', - 'csv_column_bill-id' => 'Bill ID (matching Firefly)', - 'csv_column_bill-name' => 'Bill name', - 'csv_column_budget-id' => 'Budget ID (matching Firefly)', - 'csv_column_budget-name' => 'Budget name', - 'csv_column_category-id' => 'Category ID (matching Firefly)', - 'csv_column_category-name' => 'Category name', - 'csv_column_currency-code' => 'Currency code (ISO 4217)', - 'csv_column_currency-id' => 'Currency ID (matching Firefly)', - 'csv_column_currency-name' => 'Currency name (matching Firefly)', - 'csv_column_currency-symbol' => 'Currency symbol (matching Firefly)', - 'csv_column_date-rent' => 'Rent calculation date', - 'csv_column_date-transaction' => 'Date', - 'csv_column_description' => 'Description', - 'csv_column_opposing-iban' => 'Opposing account (IBAN)', - 'csv_column_opposing-id' => 'Opposing account ID (matching Firefly)', - 'csv_column_opposing-name' => 'Opposing account (name)', - 'csv_column_rabo-debet-credit' => 'Rabobank specific debet/credit indicator', - 'csv_column_ing-debet-credit' => 'ING specific debet/credit indicator', - 'csv_column_sepa-ct-id' => 'SEPA Credit Transfer end-to-end ID', - 'csv_column_sepa-ct-op' => 'SEPA Credit Transfer opposing account', - 'csv_column_sepa-db' => 'SEPA Direct Debet', - 'csv_column_tags-comma' => 'Tags (comma separated)', - 'csv_column_tags-space' => 'Tags (space separated)', - 'csv_column_account-number' => 'Asset account (account number)', - 'csv_column_opposing-number' => 'Opposing account (account number)', - 'csv_specifix_RabobankDescription' => 'Select this when you\'re importing Rabobank CSV export files.', - 'csv_specifix_AbnAmroDescription' => 'Select this when you\'re importing ABN AMRO CSV export files.', - 'csv_specifix_Dummy' => 'Checking this has no effect whatsoever.', - 'csv_import_account_help' => 'If your CSV file does NOT contain information about your asset account(s), use this dropdown to select to which account the transactions in the CSV belong to.', - 'csv_delimiter_help' => 'Choose the field delimiter that is used in your input file. If not sure, comma is the safest option.', - 'csv_date_parse_error' => 'Could not parse a valid date from ":value", using the format ":format". Are you sure your CSV is correct?', - 'could_not_recover' => 'Could not continue from the previous step. Your progress has been lost :(. The log files will tell you what happened.', - 'must_select_roles' => 'You must select some roles for your file content, or the process cannot continue.', - 'invalid_mapping' => 'You have submitted an invalid mapping. The process cannot continue.', - 'no_file_uploaded' => 'It seems you did not upload a file.', - + // import routine + 'import_data' => 'Import data', + 'import' => 'Import', + 'import_intro_text' => 'Some intro here', + 'import_file_help' => 'Select your file', + // create new stuff: 'create_new_withdrawal' => 'Create new withdrawal', diff --git a/resources/lang/en_US/form.php b/resources/lang/en_US/form.php index b60433f727..d261d04399 100644 --- a/resources/lang/en_US/form.php +++ b/resources/lang/en_US/form.php @@ -71,13 +71,9 @@ return [ 'code' => 'Code', 'iban' => 'IBAN', 'accountNumber' => 'Account number', - 'csv' => 'CSV file', 'has_headers' => 'Headers', 'date_format' => 'Date format', - 'csv_config' => 'CSV import configuration', 'specifix' => 'Bank- or file specific fixes', - 'csv_import_account' => 'Default import account', - 'csv_delimiter' => 'CSV field delimiter', 'attachments[]' => 'Attachments', 'store_new_withdrawal' => 'Store new withdrawal', 'store_new_deposit' => 'Store new deposit', @@ -102,9 +98,6 @@ return [ 'include_config' => 'Include configuration file', 'include_old_uploads' => 'Include imported data', 'accounts' => 'Export transactions from these accounts', - 'csv_comma' => 'A comma (,)', - 'csv_semicolon' => 'A semicolon (;)', - 'csv_tab' => 'A tab (invisible)', 'delete_account' => 'Delete account ":name"', 'delete_bill' => 'Delete bill ":name"', 'delete_budget' => 'Delete budget ":name"', diff --git a/resources/lang/en_US/help.php b/resources/lang/en_US/help.php index bf2fff9e38..d1fa572177 100644 --- a/resources/lang/en_US/help.php +++ b/resources/lang/en_US/help.php @@ -55,11 +55,6 @@ return [ 'categories-show' => 'categories.show', 'categories-show-date' => 'categories.show.date', 'categories-noCategory' => 'categories.noCategory', - 'csv-index' => 'csv.index', - 'csv-column-roles' => 'csv.column-roles', - 'csv-map' => 'csv.map', - 'csv-download-config-page' => 'csv.download-config-page', - 'csv-process' => 'csv.process', 'currency-index' => 'currency.index', 'currency-create' => 'currency.create', 'currency-edit' => 'currency.edit', diff --git a/resources/views/import/csv/configure.twig b/resources/views/import/csv/configure.twig new file mode 100644 index 0000000000..1a4e95f42b --- /dev/null +++ b/resources/views/import/csv/configure.twig @@ -0,0 +1,84 @@ +{% extends "./layout/default.twig" %} + +{% block breadcrumbs %} + {{ Breadcrumbs.renderIfExists(Route.getCurrentRoute.getName, job) }} +{% endblock %} + +{% block content %} + +
+ {{ 'import_csv_configure_intro' }} +
+