Migration improvements: (#3428)

- Refactored exceptions
- Changed failed.blade.php
- Removed report() method from exceptions
- Added new force flag for MigrationController.php
This commit is contained in:
David Bomba 2020-03-06 07:30:32 +11:00 committed by GitHub
parent 20c818cf97
commit 280271718b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 94 additions and 98 deletions

View File

@ -7,13 +7,5 @@ use Throwable;
class MigrationValidatorFailed extends Exception class MigrationValidatorFailed extends Exception
{ {
public function __construct($message = "", $code = 0, Throwable $previous = null) // ..
{
parent::__construct($message, $code, $previous);
}
public function report()
{
return $this->message;
}
} }

View File

@ -7,13 +7,5 @@ use Throwable;
class NonExistingMigrationFile extends Exception class NonExistingMigrationFile extends Exception
{ {
public function __construct($message = "", $code = 0, Throwable $previous = null) // ..
{
parent::__construct($message, $code, $previous);
}
public function report()
{
return 'Migration file doesn\'t exist or it is corrupted.';
}
} }

View File

@ -7,22 +7,5 @@ use Throwable;
class ProcessingMigrationArchiveFailed extends Exception class ProcessingMigrationArchiveFailed extends Exception
{ {
/** // ..
* @var Throwable
*/
private $previous;
public function __construct($message = "", $code = 0, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
$this->message = $message;
$this->code = $code;
$this->previous = $previous;
}
public function report()
{
return 'Unable to open migration archive.';
}
} }

View File

@ -7,18 +7,5 @@ use Throwable;
class ResourceDependencyMissing extends Exception class ResourceDependencyMissing extends Exception
{ {
private $resource; // ..
private $dependency;
public function __construct($resource, $dependency)
{
parent::__construct();
$this->resource = $resource;
$this->dependency = $dependency;
}
public function report()
{
return "Resource '{$this->resource}' depends on '{$this->dependency}'.";
}
} }

View File

@ -7,19 +7,5 @@ use Throwable;
class ResourceNotAvailableForMigration extends Exception class ResourceNotAvailableForMigration extends Exception
{ {
private $resource; // ..
public function __construct($resource)
{
parent::__construct();
$this->resource = $resource;
}
public function report()
{
// TODO: Handle this nicely, throw response, etc.
return "Resource {$this->resource} is not available for the migration.";
}
} }

View File

@ -15,6 +15,7 @@ use App\Exceptions\MigrationValidatorFailed;
use App\Exceptions\NonExistingMigrationFile; use App\Exceptions\NonExistingMigrationFile;
use App\Exceptions\ProcessingMigrationArchiveFailed; use App\Exceptions\ProcessingMigrationArchiveFailed;
use App\Exceptions\ResourceNotAvailableForMigration; use App\Exceptions\ResourceNotAvailableForMigration;
use App\Factory\CompanyFactory;
use App\Http\Requests\Account\CreateAccountRequest; use App\Http\Requests\Account\CreateAccountRequest;
use App\Http\Requests\Migration\UploadMigrationFileRequest; use App\Http\Requests\Migration\UploadMigrationFileRequest;
use App\Jobs\Account\CreateAccount; use App\Jobs\Account\CreateAccount;
@ -192,7 +193,7 @@ class MigrationController extends BaseController
*/ */
public function startMigration(Request $request, Company $company) public function startMigration(Request $request, Company $company)
{ {
if ($request->has('force')) if ($request->has('force') && !empty($request->force))
$this->purgeCompany($company); $this->purgeCompany($company);
$migration_file = $request->file('migration') $migration_file = $request->file('migration')
@ -201,12 +202,11 @@ class MigrationController extends BaseController
if (app()->environment() == 'testing') return; if (app()->environment() == 'testing') return;
$user = auth()->user(); $user = auth()->user();
$company = $company;
StartMigration::dispatch($migration_file, $user, $company); StartMigration::dispatch($migration_file, $user, $company);
return response()->json([ return response()->json([
'_id' => Str::uuid(), '_id' => Str::uuid(),
'method' => config('queue.default'), 'method' => config('queue.default'),
'started_at' => now(), 'started_at' => now(),
], 200); ], 200);

View File

@ -131,14 +131,19 @@ class Import implements ShouldQueue
foreach ($this->data as $key => $resource) { foreach ($this->data as $key => $resource) {
if (!in_array($key, $this->available_imports)) { if (!in_array($key, $this->available_imports)) {
throw new ResourceNotAvailableForMigration($key); throw new ResourceNotAvailableForMigration("Resource {$key} is not available for migration.");
} }
\Log::error($key);
\Log::error($key);
$method = sprintf("process%s", Str::ucfirst(Str::camel($key))); $method = sprintf("process%s", Str::ucfirst(Str::camel($key)));
$this->{$method}($resource); $this->{$method}($resource);
info("$key done!!");
} }
info('Completed🚀🚀🚀🚀🚀 at ' . now());
} }
/** /**
@ -155,7 +160,7 @@ class Import implements ShouldQueue
if ($validator->fails()) { if ($validator->fails()) {
// \Log::error($validator->errors()); // \Log::error($validator->errors());
throw new MigrationValidatorFailed($validator->errors()); throw new MigrationValidatorFailed(json_encode($validator->errors()));
} }
if (isset($data['account_id'])) if (isset($data['account_id']))
@ -185,7 +190,7 @@ class Import implements ShouldQueue
$validator = Validator::make($data, $rules); $validator = Validator::make($data, $rules);
if ($validator->fails()) { if ($validator->fails()) {
throw new MigrationValidatorFailed($validator->errors()); throw new MigrationValidatorFailed(json_encode($validator->errors()));
} }
foreach ($data as $resource) { foreach ($data as $resource) {
@ -231,7 +236,7 @@ class Import implements ShouldQueue
$validator = Validator::make($data, $rules); $validator = Validator::make($data, $rules);
if ($validator->fails()) { if ($validator->fails()) {
throw new MigrationValidatorFailed($validator->errors()); throw new MigrationValidatorFailed(json_encode($validator->errors()));
} }
$user_repository = new UserRepository(); $user_repository = new UserRepository();
@ -324,7 +329,7 @@ class Import implements ShouldQueue
$validator = Validator::make($data, $rules); $validator = Validator::make($data, $rules);
if ($validator->fails()) { if ($validator->fails()) {
throw new MigrationValidatorFailed($validator->errors()); throw new MigrationValidatorFailed(json_encode($validator->errors()));
} }
$product_repository = new ProductRepository(); $product_repository = new ProductRepository();
@ -358,7 +363,7 @@ class Import implements ShouldQueue
$validator = Validator::make($data, $rules); $validator = Validator::make($data, $rules);
if ($validator->fails()) { if ($validator->fails()) {
throw new MigrationValidatorFailed($validator->errors()); throw new MigrationValidatorFailed(json_encode($validator->errors()));
} }
$invoice_repository = new InvoiceRepository(); $invoice_repository = new InvoiceRepository();
@ -368,7 +373,7 @@ class Import implements ShouldQueue
$modified = $resource; $modified = $resource;
if (array_key_exists('client_id', $resource) && !array_key_exists('clients', $this->ids)) { if (array_key_exists('client_id', $resource) && !array_key_exists('clients', $this->ids)) {
throw new ResourceDependencyMissing(array_key_first($data), 'clients'); throw new ResourceDependencyMissing('Processing invoices failed, because of missing dependency - clients.');
} }
$modified['client_id'] = $this->transformId('clients', $resource['client_id']); $modified['client_id'] = $this->transformId('clients', $resource['client_id']);
@ -405,7 +410,7 @@ class Import implements ShouldQueue
$validator = Validator::make($data, $rules); $validator = Validator::make($data, $rules);
if ($validator->fails()) { if ($validator->fails()) {
throw new MigrationValidatorFailed($validator->errors()); throw new MigrationValidatorFailed(json_encode($validator->errors()));
} }
$credit_repository = new CreditRepository(); $credit_repository = new CreditRepository();
@ -415,7 +420,7 @@ class Import implements ShouldQueue
$modified = $resource; $modified = $resource;
if (array_key_exists('client_id', $resource) && !array_key_exists('clients', $this->ids)) { if (array_key_exists('client_id', $resource) && !array_key_exists('clients', $this->ids)) {
throw new ResourceDependencyMissing(array_key_first($data), 'clients'); throw new ResourceDependencyMissing('Processing credits failed, because of missing dependency - clients.');
} }
$modified['client_id'] = $this->transformId('clients', $resource['client_id']); $modified['client_id'] = $this->transformId('clients', $resource['client_id']);
@ -451,7 +456,7 @@ class Import implements ShouldQueue
$validator = Validator::make($data, $rules); $validator = Validator::make($data, $rules);
if ($validator->fails()) { if ($validator->fails()) {
throw new MigrationValidatorFailed($validator->errors()); throw new MigrationValidatorFailed(json_encode($validator->errors()));
} }
$quote_repository = new QuoteRepository(); $quote_repository = new QuoteRepository();
@ -461,7 +466,7 @@ class Import implements ShouldQueue
$modified = $resource; $modified = $resource;
if (array_key_exists('client_id', $resource) && !array_key_exists('clients', $this->ids)) { if (array_key_exists('client_id', $resource) && !array_key_exists('clients', $this->ids)) {
throw new ResourceDependencyMissing(array_key_first($data), 'clients'); throw new ResourceDependencyMissing('Processing quotes failed, because of missing dependency - clients.');
} }
$modified['client_id'] = $this->transformId('clients', $resource['client_id']); $modified['client_id'] = $this->transformId('clients', $resource['client_id']);
@ -502,7 +507,7 @@ class Import implements ShouldQueue
$validator = Validator::make($data, $rules); $validator = Validator::make($data, $rules);
if ($validator->fails()) { if ($validator->fails()) {
throw new MigrationValidatorFailed($validator->errors()); throw new MigrationValidatorFailed(json_encode($validator->errors()));
} }
$payment_repository = new PaymentRepository(new CreditRepository()); $payment_repository = new PaymentRepository(new CreditRepository());
@ -512,7 +517,7 @@ class Import implements ShouldQueue
$modified = $resource; $modified = $resource;
if (array_key_exists('client_id', $resource) && !array_key_exists('clients', $this->ids)) { if (array_key_exists('client_id', $resource) && !array_key_exists('clients', $this->ids)) {
throw new ResourceDependencyMissing(array_key_first($data), 'clients'); throw new ResourceDependencyMissing('Processing payments failed, because of missing dependency - clients.');
} }
$modified['client_id'] = $this->transformId('clients', $resource['client_id']); $modified['client_id'] = $this->transformId('clients', $resource['client_id']);
@ -557,11 +562,11 @@ class Import implements ShouldQueue
$modified = $resource; $modified = $resource;
if (array_key_exists('invoice_id', $resource) && $resource['invoice_id'] && !array_key_exists('invoices', $this->ids)) { if (array_key_exists('invoice_id', $resource) && $resource['invoice_id'] && !array_key_exists('invoices', $this->ids)) {
throw new ResourceDependencyMissing(array_key_first($data), 'invoices'); throw new ResourceDependencyMissing('Processing documents failed, because of missing dependency - invoices.');
} }
if (array_key_exists('expense_id', $resource) && $resource['expense_id'] && !array_key_exists('expenses', $this->ids)) { if (array_key_exists('expense_id', $resource) && $resource['expense_id'] && !array_key_exists('expenses', $this->ids)) {
throw new ResourceDependencyMissing(array_key_first($data), 'expenses'); throw new ResourceDependencyMissing('Processing documents failed, because of missing dependency - expenses.');
} }
/** Remove because of polymorphic joins. */ /** Remove because of polymorphic joins. */
@ -611,7 +616,7 @@ class Import implements ShouldQueue
$validator = Validator::make($data, $rules); $validator = Validator::make($data, $rules);
if ($validator->fails()) { if ($validator->fails()) {
throw new MigrationValidatorFailed($validator->errors()); throw new MigrationValidatorFailed(json_encode($validator->errors()));
} }
foreach ($data as $resource) { foreach ($data as $resource) {

View File

@ -63,7 +63,7 @@ class StartMigration implements ShouldQueue
auth()->login($this->user, false); auth()->login($this->user, false);
auth()->user()->setCompany($this->company); auth()->user()->setCompany($this->company);
$zip = new \ZipArchive(); $zip = new \ZipArchive();
$archive = $zip->open($this->filepath); $archive = $zip->open($this->filepath);
@ -71,7 +71,7 @@ class StartMigration implements ShouldQueue
try { try {
if (!$archive) if (!$archive)
throw new ProcessingMigrationArchiveFailed(); throw new ProcessingMigrationArchiveFailed('Processing migration archive failed. Migration file is possibly corrupted.');
$zip->extractTo(storage_path("migrations/{$filename}")); $zip->extractTo(storage_path("migrations/{$filename}"));
$zip->close(); $zip->close();
@ -81,10 +81,9 @@ class StartMigration implements ShouldQueue
$this->start($filename); $this->start($filename);
} catch (NonExistingMigrationFile | ProcessingMigrationArchiveFailed | ResourceNotAvailableForMigration | MigrationValidatorFailed | ResourceDependencyMissing $e) { } catch (NonExistingMigrationFile | ProcessingMigrationArchiveFailed | ResourceNotAvailableForMigration | MigrationValidatorFailed | ResourceDependencyMissing $e) {
Mail::to($this->user) Mail::to($this->user)->send(new MigrationFailed($e, $e->getMessage()));
->send(new MigrationFailed($e, $e->getMessage()));
if (app()->environment() !== 'production') info($e->getMessage());
if(app()->environment() !== 'production') info($e->getMessage());
} }
} }
@ -98,7 +97,7 @@ class StartMigration implements ShouldQueue
$file = storage_path("migrations/$filename/migration.json"); $file = storage_path("migrations/$filename/migration.json");
if (!file_exists($file)) if (!file_exists($file))
throw new NonExistingMigrationFile(); throw new NonExistingMigrationFile('Migration file does not exist, or it is corrupted.');
$handle = fopen($file, "r"); $handle = fopen($file, "r");
$file = fread($handle, filesize($file)); $file = fread($handle, filesize($file));

View File

@ -11,18 +11,17 @@ class MigrationFailed extends Mailable
use Queueable, SerializesModels; use Queueable, SerializesModels;
public $exception; public $exception;
public $message; public $content;
/** /**
* Create a new message instance. * Create a new message instance.
* *
* @param $message * @param $content
* @param $exception * @param $exception
*/ */
public function __construct($exception, $message = null) public function __construct($exception, $content = null)
{ {
$this->exception = $exception; $this->exception = $exception;
$this->message = 'Oops, looks like something went wrong with your migration. Please try again, later.';
} }
/** /**

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateJobsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('jobs', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('queue')->index();
$table->longText('payload');
$table->unsignedTinyInteger('attempts');
$table->unsignedInteger('reserved_at')->nullable();
$table->unsignedInteger('available_at');
$table->unsignedInteger('created_at');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('jobs');
}
}

View File

@ -2,6 +2,6 @@ Whoops!
Looks like your migration failed. Looks like your migration failed.
<pre> <pre>
{!! $exception->report() !!} {!! $exception->getMessage() !!}
{!! $message !!} {!! $content !!}
</pre> </pre>

View File

@ -504,4 +504,21 @@ class ImportTest extends TestCase
$this->assertTrue(true, 'Documents importing not completed yet. Missing expenses.'); $this->assertTrue(true, 'Documents importing not completed yet. Missing expenses.');
} }
public function testExceptionMailSending()
{
Mail::fake();
$data['panda_bears'] = [
'name' => 'Awesome Panda Bear',
];
try {
Import::dispatchNow($data, $this->company, $this->user);
}
catch (ResourceNotAvailableForMigration $e) {
Mail::to($this->user)->send(new MigrationFailed($e, $e->getMessage()));
$this->assertTrue(true);
}
}
} }