1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 13:12:50 +01:00

Merge pull request #6580 from turbo124/v5-develop

Hosted Migration Console Command
This commit is contained in:
David Bomba 2021-09-05 19:47:13 +10:00 committed by GitHub
commit 424b08ff6f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 232 additions and 7 deletions

View File

@ -0,0 +1,131 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Console\Commands;
use App\DataMapper\CompanySettings;
use App\Exceptions\MigrationValidatorFailed;
use App\Exceptions\NonExistingMigrationFile;
use App\Exceptions\ProcessingMigrationArchiveFailed;
use App\Exceptions\ResourceDependencyMissing;
use App\Exceptions\ResourceNotAvailableForMigration;
use App\Jobs\Util\Import;
use App\Jobs\Util\StartMigration;
use App\Libraries\MultiDB;
use App\Mail\MigrationFailed;
use App\Models\Account;
use App\Models\Company;
use App\Models\CompanyToken;
use App\Models\User;
use App\Utils\Traits\AppSetup;
use App\Utils\Traits\MakesHash;
use DirectoryIterator;
use Faker\Factory;
use Faker\Generator;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
use ZipArchive;
class HostedMigrations extends Command
{
use MakesHash;
use AppSetup;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'migrations:hosted-import {--email=}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Import a v4 migration file';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->buildCache();
if(!MultiDB::userFindAndSetDb($this->option('email'))){
$this->info("Could not find a user with that email address");
return;
}
$user = User::where('email', $this->option('email'))->first();
if(!$user){
$this->info("There was a problem getting the user, did you set the right DB?");
return;
}
$path = public_path('storage/migrations/import');
nlog(public_path('storage/migrations/import'));
$directory = new DirectoryIterator($path);
foreach ($directory as $file) {
if ($file->getExtension() === 'zip') {
$company = $user->companies()->first();
$this->info('Started processing: '.$file->getBasename().' at '.now());
$zip = new ZipArchive();
$archive = $zip->open($file->getRealPath());
try {
if (! $archive) {
throw new ProcessingMigrationArchiveFailed('Processing migration archive failed. Migration file is possibly corrupted.');
}
$filename = pathinfo($file->getRealPath(), PATHINFO_FILENAME);
$zip->extractTo(public_path("storage/migrations/{$filename}"));
$zip->close();
$import_file = public_path("storage/migrations/$filename/migration.json");
Import::dispatch($import_file, $user->companies()->first(), $user);
unlink(public_path("storage/migrations/$filename/migration.json"));
unlink($file->getRealPath());
} catch (NonExistingMigrationFile | ProcessingMigrationArchiveFailed | ResourceNotAvailableForMigration | MigrationValidatorFailed | ResourceDependencyMissing $e) {
\Mail::to($this->user)->send(new MigrationFailed($e, $e->getMessage()));
if (app()->environment() !== 'production') {
info($e->getMessage());
}
}
}
}
}
}

View File

@ -52,9 +52,9 @@ class QueryLogging
$timeEnd = microtime(true);
$time = $timeEnd - $timeStart;
nlog("Query count = {$count}");
// nlog("Query count = {$count}");
if($count > 250){
if($count > 175){
nlog("Quer count = {$count}");
nlog($queries);
}

View File

@ -36,7 +36,7 @@ class WebhookHandler implements ShouldQueue
private $company;
public $tries = 3; //number of retries
public $tries = 1; //number of retries
public $backoff = 10; //seconds to wait until retry

View File

@ -122,6 +122,13 @@ class Activity extends StaticModel
return $this->hasOne(Backup::class);
}
public function history()
{
return $this->hasOne(Backup::class);
}
/**
* @return mixed
*/

View File

@ -54,7 +54,7 @@ class CompanyPresenter extends EntityPresenter
$settings = $this->entity->settings;
}
if(config('ninja.is_docker'))
if(config('ninja.is_docker') || config('ninja.local_download'))
return $this->logo($settings);
$context_options =array(

View File

@ -12,6 +12,7 @@
namespace App\Transformers;
use App\Models\Activity;
use App\Models\Backup;
use App\Utils\Traits\MakesHash;
class ActivityTransformer extends EntityTransformer
@ -23,7 +24,9 @@ class ActivityTransformer extends EntityTransformer
/**
* @var array
*/
protected $availableIncludes = [];
protected $availableIncludes = [
'history'
];
/**
* @param Activity $activity
@ -55,4 +58,11 @@ class ActivityTransformer extends EntityTransformer
];
}
public function includeHistory(Activity $activity)
{
$transformer = new InvoiceHistoryTransformer($this->serializer);
return $this->includeItem($activity->backup, $transformer, Backup::class);
}
}

View File

@ -20,10 +20,12 @@ class InvoiceHistoryTransformer extends EntityTransformer
use MakesHash;
protected $defaultIncludes = [
'activity',
// 'activity',
];
protected $availableIncludes = [];
protected $availableIncludes = [
'activity',
];
public function transform(Backup $backup)
{

View File

@ -132,6 +132,7 @@ class HtmlEngine
$data['$view_link'] = ['value' => '<a class="button" href="'.$this->invitation->getLink().'">'.ctrans('texts.view_invoice').'</a>', 'label' => ctrans('texts.view_invoice')];
$data['$viewLink'] = &$data['$view_link'];
$data['$viewButton'] = &$data['$view_link'];
$data['$paymentButton'] = &$data['$view_link'];
$data['$view_url'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_invoice')];
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: '&nbsp;', 'label' => ctrans('texts.invoice_date')];
@ -148,6 +149,8 @@ class HtmlEngine
$data['$terms'] = &$data['$entity.terms'];
$data['$view_link'] = ['value' => '<a class="button" href="'.$this->invitation->getLink().'">'.ctrans('texts.view_quote').'</a>', 'label' => ctrans('texts.view_quote')];
$data['$viewLink'] = &$data['$view_link'];
$data['$viewButton'] = &$data['$view_link'];
$data['$approveButton'] = ['value' => '<a class="button" href="'.$this->invitation->getLink().'">'.ctrans('texts.view_quote').'</a>', 'label' => ctrans('texts.approve')];
$data['$view_url'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_quote')];
$data['$date'] = ['value' => $this->translateDate($this->entity->date, $this->entity->client->date_format(), $this->entity->client->locale()) ?: '&nbsp;', 'label' => ctrans('texts.quote_date')];
}
@ -159,6 +162,7 @@ class HtmlEngine
$data['$entity.terms'] = ['value' => $this->entity->terms ?: '', 'label' => ctrans('texts.credit_terms')];
$data['$terms'] = &$data['$entity.terms'];
$data['$view_link'] = ['value' => '<a class="button" href="'.$this->invitation->getLink().'">'.ctrans('texts.view_credit').'</a>', 'label' => ctrans('texts.view_credit')];
$data['$viewButton'] = &$data['$view_link'];
$data['$viewLink'] = &$data['$view_link'];
$data['$view_url'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_credit')];
// $data['$view_link'] = ['value' => $this->invitation->getLink(), 'label' => ctrans('texts.view_credit')];

View File

@ -36,6 +36,7 @@ return [
'phantomjs_pdf_generation' => env('PHANTOMJS_PDF_GENERATION', true),
'trusted_proxies' => env('TRUSTED_PROXIES', false),
'is_docker' => env('IS_DOCKER', false),
'local_download' => env('LOCAL_DOWNLOAD', false),
'sentry_dsn' => env('SENTRY_LARAVEL_DSN', 'https://9b4e15e575214354a7d666489783904a@sentry.invoicing.co/6'),
'environment' => env('NINJA_ENVIRONMENT', 'selfhost'), // 'hosted', 'development', 'selfhost', 'reseller'
'preconfigured_install' => env('PRECONFIGURED_INSTALL',false),

70
config/querydetector.php Normal file
View File

@ -0,0 +1,70 @@
<?php
return [
/*
* Enable or disable the query detection.
* If this is set to "null", the app.debug config value will be used.
*/
'enabled' => env('QUERY_DETECTOR_ENABLED', false),
/*
* Threshold level for the N+1 query detection. If a relation query will be
* executed more then this amount, the detector will notify you about it.
*/
'threshold' => (int) env('QUERY_DETECTOR_THRESHOLD', 1),
/*
* Here you can whitelist model relations.
*
* Right now, you need to define the model relation both as the class name and the attribute name on the model.
* So if an "Author" model would have a "posts" relation that points to a "Post" class, you need to add both
* the "posts" attribute and the "Post::class", since the relation can get resolved in multiple ways.
*/
'except' => [
//Author::class => [
// Post::class,
// 'posts',
//]
],
/*
* Here you can set a specific log channel to write to
* in case you are trying to isolate queries or have a lot
* going on in the laravel.log. Defaults to laravel.log though.
*/
'log_channel' => env('QUERY_DETECTOR_LOG_CHANNEL', 'daily'),
/*
* Define the output format that you want to use. Multiple classes are supported.
* Available options are:
*
* Alert:
* Displays an alert on the website
* \BeyondCode\QueryDetector\Outputs\Alert::class
*
* Console:
* Writes the N+1 queries into your browsers console log
* \BeyondCode\QueryDetector\Outputs\Console::class
*
* Clockwork: (make sure you have the itsgoingd/clockwork package installed)
* Writes the N+1 queries warnings to Clockwork log
* \BeyondCode\QueryDetector\Outputs\Clockwork::class
*
* Debugbar: (make sure you have the barryvdh/laravel-debugbar package installed)
* Writes the N+1 queries into a custom messages collector of Debugbar
* \BeyondCode\QueryDetector\Outputs\Debugbar::class
*
* JSON:
* Writes the N+1 queries into the response body of your JSON responses
* \BeyondCode\QueryDetector\Outputs\Json::class
*
* Log:
* Writes the N+1 queries into the Laravel.log file
* \BeyondCode\QueryDetector\Outputs\Log::class
*/
'output' => [
//\BeyondCode\QueryDetector\Outputs\Alert::class,
\BeyondCode\QueryDetector\Outputs\Log::class,
//\BeyondCode\QueryDetector\Outputs\Json::class,
]
];