Added ImportData job to use queue

This commit is contained in:
Hillel Coren 2017-04-02 16:54:07 +03:00
parent 2f838416b0
commit 7a13d93082
8 changed files with 219 additions and 83 deletions

View File

@ -2,59 +2,88 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Services\ImportService; use App\Services\ImportService;
use App\Jobs\ImportData;
use Exception; use Exception;
use Input; use Input;
use Redirect; use Redirect;
use Session; use Session;
use Utils; use Utils;
use View; use View;
use Auth;
class ImportController extends BaseController class ImportController extends BaseController
{ {
public function __construct(ImportService $importService) public function __construct(ImportService $importService)
{ {
//parent::__construct();
$this->importService = $importService; $this->importService = $importService;
} }
public function doImport() public function doImport(Request $request)
{ {
$source = Input::get('source'); $source = Input::get('source');
$files = []; $files = [];
$timestamp = time();
foreach (ImportService::$entityTypes as $entityType) { foreach (ImportService::$entityTypes as $entityType) {
if (Input::file("{$entityType}_file")) { $fileName = $entityType;
$files[$entityType] = Input::file("{$entityType}_file")->getRealPath(); if ($request->hasFile($fileName)) {
if ($source === IMPORT_CSV) { $file = $request->file($fileName);
Session::forget("{$entityType}-data"); $destinationPath = storage_path() . '/import';
$extension = $file->getClientOriginalExtension();
if (! in_array($extension, ['csv', 'xls', 'json'])) {
continue;
} }
$newFileName = sprintf('%s_%s_%s.%s', Auth::user()->account_id, $timestamp, $fileName, $extension);
$file->move($destinationPath, $newFileName);
$files[$entityType] = $newFileName;
} }
} }
if (! count($files)) { if (! count($files)) {
Session::flash('error', trans('texts.select_file')); Session::flash('error', trans('texts.select_file'));
return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT); return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT);
} }
try { try {
if ($source === IMPORT_CSV) { if ($source === IMPORT_CSV) {
$data = $this->importService->mapCSV($files); $data = $this->importService->mapCSV($files);
return View::make('accounts.import_map', [
return View::make('accounts.import_map', ['data' => $data]); 'data' => $data,
'timestamp' => $timestamp,
]);
} elseif ($source === IMPORT_JSON) { } elseif ($source === IMPORT_JSON) {
$includeData = filter_var(Input::get('data'), FILTER_VALIDATE_BOOLEAN); $includeData = filter_var(Input::get('data'), FILTER_VALIDATE_BOOLEAN);
$includeSettings = filter_var(Input::get('settings'), FILTER_VALIDATE_BOOLEAN); $includeSettings = filter_var(Input::get('settings'), FILTER_VALIDATE_BOOLEAN);
if (config('queue.default') === 'sync') {
$results = $this->importService->importJSON($files[IMPORT_JSON], $includeData, $includeSettings); $results = $this->importService->importJSON($files[IMPORT_JSON], $includeData, $includeSettings);
$message = $this->importService->presentResults($results, $includeSettings);
return $this->showResult($results, $includeSettings);
} else { } else {
$results = $this->importService->importFiles($source, $files); $settings = [
'files' => $files,
return $this->showResult($results); 'include_data' => $includeData,
'include_settings' => $includeSettings,
];
$this->dispatch(new ImportData(Auth::user(), IMPORT_JSON, $settings));
$message = 'started...';
} }
} else {
if (config('queue.default') === 'sync') {
$results = $this->importService->importFiles($source, $files);
$message = $this->importService->presentResults($results);
} else {
$settings = [
'files' => $files,
'source' => $source,
];
$this->dispatch(new ImportData(Auth::user(), false, $settings));
$message = 'started...';
}
}
return redirect('/settings/' . ACCOUNT_IMPORT_EXPORT)->withWarning($message);
} catch (Exception $exception) { } catch (Exception $exception) {
Utils::logError($exception); Utils::logError($exception);
Session::flash('error', $exception->getMessage()); Session::flash('error', $exception->getMessage());
@ -65,13 +94,24 @@ class ImportController extends BaseController
public function doImportCSV() public function doImportCSV()
{ {
try {
$map = Input::get('map'); $map = Input::get('map');
$headers = Input::get('headers'); $headers = Input::get('headers');
$timestamp = Input::get('timestamp');
if (config('queue.default') === 'sync') {
$results = $this->importService->importCSV($map, $headers, $timestamp);
$message = $this->importService->presentResults($results);
} else {
$settings = [
'timestamp' => $timestamp,
'map' => $map,
'headers' => $headers,
];
$this->dispatch(new ImportData(Auth::user(), IMPORT_CSV, $settings));
$message = 'started...';
}
try { return redirect('/settings/' . ACCOUNT_IMPORT_EXPORT)->withWarning($message);
$results = $this->importService->importCSV($map, $headers);
return $this->showResult($results);
} catch (Exception $exception) { } catch (Exception $exception) {
Utils::logError($exception); Utils::logError($exception);
Session::flash('error', $exception->getMessage()); Session::flash('error', $exception->getMessage());
@ -79,36 +119,4 @@ class ImportController extends BaseController
return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT); return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT);
} }
} }
private function showResult($results, $includeSettings = false)
{
$message = '';
$skipped = [];
if ($includeSettings) {
$message = trans('texts.imported_settings') . '<br/>';
}
foreach ($results as $entityType => $entityResults) {
if ($count = count($entityResults[RESULT_SUCCESS])) {
$message .= trans("texts.created_{$entityType}s", ['count' => $count]) . '<br/>';
}
if (count($entityResults[RESULT_FAILURE])) {
$skipped = array_merge($skipped, $entityResults[RESULT_FAILURE]);
}
}
if (count($skipped)) {
$message .= '<p/>' . trans('texts.failed_to_import') . '<br/>';
foreach ($skipped as $skip) {
$message .= json_encode($skip) . '<br/>';
}
}
if ($message) {
Session::flash('warning', $message);
}
return Redirect::to('/settings/' . ACCOUNT_IMPORT_EXPORT);
}
} }

View File

@ -302,6 +302,7 @@ class OnlinePaymentController extends BaseController
} }
Auth::onceUsingId($account->users[0]->id); Auth::onceUsingId($account->users[0]->id);
$account->loadLocalizationSettings();
$product = Product::scope(Input::get('product_id'))->first(); $product = Product::scope(Input::get('product_id'))->first();
if (! $product) { if (! $product) {

80
app/Jobs/ImportData.php Normal file
View File

@ -0,0 +1,80 @@
<?php
namespace App\Jobs;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Monolog\Logger;
use App\Services\ImportService;
use App\Ninja\Mailers\UserMailer;
use Auth;
/**
* Class SendInvoiceEmail.
*/
class ImportData extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
/**
* @var User
*/
protected $user;
/**
* @var string
*/
protected $type;
/**
* @var array
*/
protected $settings;
/**
* Create a new job instance.
*
* @param mixed $files
* @param mixed $settings
*/
public function __construct($user, $type, $settings)
{
$this->user = $user;
$this->type = $type;
$this->settings = $settings;
}
/**
* Execute the job.
*
* @param ContactMailer $mailer
*/
public function handle(ImportService $importService, UserMailer $userMailer)
{
$includeSettings = false;
Auth::onceUsingId($this->user->id);
$this->user->account->loadLocalizationSettings();
if ($this->type === IMPORT_JSON) {
$includeData = $this->settings['include_data'];
$includeSettings = $this->settings['include_settings'];
$files = $this->settings['files'];
$results = $importService->importJSON($files[IMPORT_JSON], $includeData, $includeSettings);
} elseif ($this->type === IMPORT_CSV) {
$map = $this->settings['map'];
$headers = $this->settings['headers'];
$timestamp = $this->settings['timestamp'];
$results = $importService->importCSV($map, $headers, $timestamp);
} else {
$source = $this->settings['source'];
$files = $this->settings['files'];
$results = $importService->importFiles($source, $files);
}
$subject = trans('texts.import_complete');
$message = $importService->presentResults($results, $includeSettings);
$userMailer->sendMessage($this->user, $subject, $message);
}
}

View File

@ -114,7 +114,7 @@ class UserMailer extends Mailer
/** /**
* @param Invitation $invitation * @param Invitation $invitation
*/ */
public function sendMessage($user, $subject, $message, $invoice) public function sendMessage($user, $subject, $message, $invoice = false)
{ {
if (! $user->email) { if (! $user->email) {
return; return;
@ -125,7 +125,7 @@ class UserMailer extends Mailer
'userName' => $user->getDisplayName(), 'userName' => $user->getDisplayName(),
'primaryMessage' => $subject, 'primaryMessage' => $subject,
'secondaryMessage' => $message, 'secondaryMessage' => $message,
'invoiceLink' => $invoice->present()->multiAccountLink, 'invoiceLink' => $invoice ? $invoice->present()->multiAccountLink : false,
]; ];
$this->sendTo($user->email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data); $this->sendTo($user->email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);

View File

@ -149,7 +149,7 @@ class ImportService
{ {
$this->initMaps(); $this->initMaps();
$file = file_get_contents($file); $file = file_get_contents(storage_path() . '/import/' . $file);
$json = json_decode($file, true); $json = json_decode($file, true);
$json = $this->removeIdFields($json); $json = $this->removeIdFields($json);
$transformer = new BaseTransformer($this->maps); $transformer = new BaseTransformer($this->maps);
@ -284,6 +284,7 @@ class ImportService
// Convert the data // Convert the data
$row_list = []; $row_list = [];
$file = storage_path() . '/import/' . $file;
Excel::load($file, function ($reader) use ($source, $entityType, &$row_list, &$results) { Excel::load($file, function ($reader) use ($source, $entityType, &$row_list, &$results) {
$this->checkData($entityType, count($reader->all())); $this->checkData($entityType, count($reader->all()));
@ -539,29 +540,13 @@ class ImportService
*/ */
public function mapFile($entityType, $filename, $columns, $map) public function mapFile($entityType, $filename, $columns, $map)
{ {
require_once app_path().'/Includes/parsecsv.lib.php'; $data = $this->getCsvData($filename);
$csv = new parseCSV();
$csv->heading = false;
$csv->auto($filename);
$headers = false; $headers = false;
$hasHeaders = false; $hasHeaders = false;
$mapped = []; $mapped = [];
if (count($csv->data) > 0) { if (count($data) > 0) {
$headers = $csv->data[0]; $headers = $data[0];
// Remove Invoice Ninja headers
if (count($headers) && count($csv->data) > 4) {
$firstCell = $headers[0];
if (strstr($firstCell, APP_NAME)) {
array_shift($csv->data); // Invoice Ninja...
array_shift($csv->data); // <blank line>
array_shift($csv->data); // Enitty Type Header
}
$headers = $csv->data[0];
}
foreach ($headers as $title) { foreach ($headers as $title) {
if (strpos(strtolower($title), 'name') > 0) { if (strpos(strtolower($title), 'name') > 0) {
$hasHeaders = true; $hasHeaders = true;
@ -583,11 +568,11 @@ class ImportService
} }
} }
Session::put("{$entityType}-data", $csv->data); //Session::put("{$entityType}-data", $csv->data);
$data = [ $data = [
'entityType' => $entityType, 'entityType' => $entityType,
'data' => $csv->data, 'data' => $data,
'headers' => $headers, 'headers' => $headers,
'hasHeaders' => $hasHeaders, 'hasHeaders' => $hasHeaders,
'columns' => $columns, 'columns' => $columns,
@ -597,6 +582,31 @@ class ImportService
return $data; return $data;
} }
private function getCsvData($filename)
{
require_once app_path().'/Includes/parsecsv.lib.php';
$csv = new parseCSV();
$csv->heading = false;
$csv->auto(storage_path() . '/import/' . $filename);
$data = $csv->data;
if (count($data) > 0) {
$headers = $data[0];
// Remove Invoice Ninja headers
if (count($headers) && count($data) > 4) {
$firstCell = $headers[0];
if (strstr($firstCell, APP_NAME)) {
array_shift($data); // Invoice Ninja...
array_shift($data); // <blank line>
array_shift($data); // Enitty Type Header
}
}
}
return $data;
}
/** /**
* @param $column * @param $column
* @param $pattern * @param $pattern
@ -642,12 +652,12 @@ class ImportService
* *
* @return array * @return array
*/ */
public function importCSV(array $maps, $headers) public function importCSV(array $maps, $headers, $timestamp)
{ {
$results = []; $results = [];
foreach ($maps as $entityType => $map) { foreach ($maps as $entityType => $map) {
$results[$entityType] = $this->executeCSV($entityType, $map, $headers[$entityType]); $results[$entityType] = $this->executeCSV($entityType, $map, $headers[$entityType], $timestamp);
} }
return $results; return $results;
@ -660,7 +670,7 @@ class ImportService
* *
* @return array * @return array
*/ */
private function executeCSV($entityType, $map, $hasHeaders) private function executeCSV($entityType, $map, $hasHeaders, $timestamp)
{ {
$results = [ $results = [
RESULT_SUCCESS => [], RESULT_SUCCESS => [],
@ -668,7 +678,9 @@ class ImportService
]; ];
$source = IMPORT_CSV; $source = IMPORT_CSV;
$data = Session::get("{$entityType}-data"); //$data = Session::get("{$entityType}-data");
$filename = sprintf('%s_%s_%s.csv', Auth::user()->account_id, $timestamp, $entityType);
$data = $this->getCsvData($filename);
$this->checkData($entityType, count($data)); $this->checkData($entityType, count($data));
$this->initMaps(); $this->initMaps();
@ -707,7 +719,7 @@ class ImportService
} }
} }
Session::forget("{$entityType}-data"); //Session::forget("{$entityType}-data");
return $results; return $results;
} }
@ -894,4 +906,32 @@ class ImportService
return $isEmpty; return $isEmpty;
} }
public function presentResults($results, $includeSettings = false)
{
$message = '';
$skipped = [];
if ($includeSettings) {
$message = trans('texts.imported_settings') . '<br/>';
}
foreach ($results as $entityType => $entityResults) {
if ($count = count($entityResults[RESULT_SUCCESS])) {
$message .= trans("texts.created_{$entityType}s", ['count' => $count]) . '<br/>';
}
if (count($entityResults[RESULT_FAILURE])) {
$skipped = array_merge($skipped, $entityResults[RESULT_FAILURE]);
}
}
if (count($skipped)) {
$message .= '<p/>' . trans('texts.failed_to_import') . '<br/>';
foreach ($skipped as $skip) {
$message .= json_encode($skip) . '<br/>';
}
}
return $message;
}
} }

View File

@ -2460,6 +2460,8 @@ $LANG = array(
'reply_to_email' => 'Reply-To Email', 'reply_to_email' => 'Reply-To Email',
'reply_to_email_help' => 'Specify the reply-to address for client emails.', 'reply_to_email_help' => 'Specify the reply-to address for client emails.',
'bcc_email_help' => 'Privately include this address with client emails.', 'bcc_email_help' => 'Privately include this address with client emails.',
'import_complete' => 'Your import has successfully completed.',
); );

View File

@ -33,7 +33,7 @@
<br/> <br/>
@foreach (\App\Services\ImportService::$entityTypes as $entityType) @foreach (\App\Services\ImportService::$entityTypes as $entityType)
{!! Former::file("{$entityType}_file") {!! Former::file($entityType)
->addGroupClass("import-file {$entityType}-file") !!} ->addGroupClass("import-file {$entityType}-file") !!}
@endforeach @endforeach

View File

@ -6,6 +6,11 @@
@include('accounts.nav', ['selected' => ACCOUNT_IMPORT_EXPORT]) @include('accounts.nav', ['selected' => ACCOUNT_IMPORT_EXPORT])
{!! Former::open('/import_csv')->addClass('warn-on-exit') !!} {!! Former::open('/import_csv')->addClass('warn-on-exit') !!}
{!! Former::populateField('timestamp', $timestamp) !!}
<div style="display:none">
{!! Former::text('timestamp') !!}
</div>
@foreach (App\Services\ImportService::$entityTypes as $entityType) @foreach (App\Services\ImportService::$entityTypes as $entityType)
@if (isset($data[$entityType])) @if (isset($data[$entityType]))