mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-16 16:13:20 +01:00
Merge branch 'v5-develop' into v5-stable
This commit is contained in:
commit
3dc49c92fa
@ -1 +1 @@
|
|||||||
5.1.72
|
5.1.74
|
166
app/Console/Commands/CheckDb.php
Normal file
166
app/Console/Commands/CheckDb.php
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
<?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://opensource.org/licenses/AAL
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App;
|
||||||
|
use App\Factory\ClientContactFactory;
|
||||||
|
use App\Models\Account;
|
||||||
|
use App\Models\Activity;
|
||||||
|
use App\Models\Backup;
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\ClientContact;
|
||||||
|
use App\Models\ClientGatewayToken;
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Models\CompanyGateway;
|
||||||
|
use App\Models\CompanyLedger;
|
||||||
|
use App\Models\CompanyToken;
|
||||||
|
use App\Models\CompanyUser;
|
||||||
|
use App\Models\Contact;
|
||||||
|
use App\Models\Credit;
|
||||||
|
use App\Models\CreditInvitation;
|
||||||
|
use App\Models\Design;
|
||||||
|
use App\Models\Document;
|
||||||
|
use App\Models\Expense;
|
||||||
|
use App\Models\ExpenseCategory;
|
||||||
|
use App\Models\Gateway;
|
||||||
|
use App\Models\GroupSetting;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\InvoiceInvitation;
|
||||||
|
use App\Models\Payment;
|
||||||
|
use App\Models\PaymentHash;
|
||||||
|
use App\Models\Paymentable;
|
||||||
|
use App\Models\Product;
|
||||||
|
use App\Models\Project;
|
||||||
|
use App\Models\Quote;
|
||||||
|
use App\Models\QuoteInvitation;
|
||||||
|
use App\Models\RecurringInvoice;
|
||||||
|
use App\Models\RecurringInvoiceInvitation;
|
||||||
|
use App\Models\Subscription;
|
||||||
|
use App\Models\SystemLog;
|
||||||
|
use App\Models\Task;
|
||||||
|
use App\Models\TaskStatus;
|
||||||
|
use App\Models\TaxRate;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\Vendor;
|
||||||
|
use App\Models\VendorContact;
|
||||||
|
use App\Models\Webhook;
|
||||||
|
use App\Utils\Ninja;
|
||||||
|
use DB;
|
||||||
|
use Exception;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Mail;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class CheckDb.
|
||||||
|
*/
|
||||||
|
class CheckDb extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'ninja:check-db';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Check MultiDB';
|
||||||
|
|
||||||
|
|
||||||
|
protected $log = '';
|
||||||
|
|
||||||
|
|
||||||
|
private $entities = [
|
||||||
|
Account::class,
|
||||||
|
Activity::class,
|
||||||
|
Backup::class,
|
||||||
|
Client::class,
|
||||||
|
ClientContact::class,
|
||||||
|
ClientGatewayToken::class,
|
||||||
|
Company::class,
|
||||||
|
CompanyGateway::class,
|
||||||
|
CompanyLedger::class,
|
||||||
|
CompanyToken::class,
|
||||||
|
CompanyUser::class,
|
||||||
|
Credit::class,
|
||||||
|
CreditInvitation::class,
|
||||||
|
Design::class,
|
||||||
|
Document::class,
|
||||||
|
Expense::class,
|
||||||
|
ExpenseCategory::class,
|
||||||
|
Gateway::class,
|
||||||
|
GroupSetting::class,
|
||||||
|
Invoice::class,
|
||||||
|
InvoiceInvitation::class,
|
||||||
|
Payment::class,
|
||||||
|
Paymentable::class,
|
||||||
|
PaymentHash::class,
|
||||||
|
Product::class,
|
||||||
|
Project::class,
|
||||||
|
Quote::class,
|
||||||
|
QuoteInvitation::class,
|
||||||
|
RecurringInvoice::class,
|
||||||
|
RecurringInvoiceInvitation::class,
|
||||||
|
Subscription::class,
|
||||||
|
SystemLog::class,
|
||||||
|
Task::class,
|
||||||
|
TaskStatus::class,
|
||||||
|
TaxRate::class,
|
||||||
|
User::class,
|
||||||
|
Vendor::class,
|
||||||
|
VendorContact::class,
|
||||||
|
WebHook::class,
|
||||||
|
];
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach($this->entities as $entity) {
|
||||||
|
|
||||||
|
$this->LogMessage("V5_DB1");
|
||||||
|
|
||||||
|
$count_db_1 = $entity::on('db-ninja-01')->count();
|
||||||
|
$count_db_2 = $entity::on('db-ninja-02a')->count();
|
||||||
|
|
||||||
|
$diff = $count_db_1 - $count_db_2;
|
||||||
|
|
||||||
|
if($diff != 0)
|
||||||
|
$this->logMessage("{$entity} DB1: {$count_db_1} - DB2: {$count_db_2} - diff = {$diff}");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach($this->entities as $entity) {
|
||||||
|
|
||||||
|
$this->LogMessage("V5_DB2");
|
||||||
|
|
||||||
|
$count_db_1 = $entity::on('db-ninja-02')->count();
|
||||||
|
$count_db_2 = $entity::on('db-ninja-01a')->count();
|
||||||
|
|
||||||
|
$diff = $count_db_1 - $count_db_2;
|
||||||
|
|
||||||
|
if($diff != 0)
|
||||||
|
$this->logMessage("{$entity} DB1: {$count_db_1} - DB2: {$count_db_2} - diff = {$diff}");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function logMessage($str)
|
||||||
|
{
|
||||||
|
$str = date('Y-m-d h:i:s').' '.$str;
|
||||||
|
$this->info($str);
|
||||||
|
$this->log .= $str."\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -75,7 +75,7 @@ class Kernel extends ConsoleKernel
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(config('queue.default') == 'database' && Ninja::isSelfHost() && config('ninja.internal_queue_enabled')) {
|
if(config('queue.default') == 'database' && Ninja::isSelfHost() && config('ninja.internal_queue_enabled') && !config('ninja.is_docker')) {
|
||||||
|
|
||||||
$schedule->command('queue:work')->everyMinute()->withoutOverlapping();
|
$schedule->command('queue:work')->everyMinute()->withoutOverlapping();
|
||||||
$schedule->command('queue:restart')->everyFiveMinutes()->withoutOverlapping();
|
$schedule->command('queue:restart')->everyFiveMinutes()->withoutOverlapping();
|
||||||
|
@ -93,6 +93,10 @@ class CompanyImport implements ShouldQueue
|
|||||||
|
|
||||||
public $pre_flight_checks_pass = true;
|
public $pre_flight_checks_pass = true;
|
||||||
|
|
||||||
|
public $force_user_coalesce = false;
|
||||||
|
|
||||||
|
public $company_owner;
|
||||||
|
|
||||||
private $importables = [
|
private $importables = [
|
||||||
// 'company',
|
// 'company',
|
||||||
'users',
|
'users',
|
||||||
@ -141,6 +145,7 @@ class CompanyImport implements ShouldQueue
|
|||||||
public function __construct(Company $company, User $user, string $hash, array $request_array)
|
public function __construct(Company $company, User $user, string $hash, array $request_array)
|
||||||
{
|
{
|
||||||
$this->company = $company;
|
$this->company = $company;
|
||||||
|
$this->user = $user;
|
||||||
$this->hash = $hash;
|
$this->hash = $hash;
|
||||||
$this->request_array = $request_array;
|
$this->request_array = $request_array;
|
||||||
$this->current_app_version = config('ninja.app_version');
|
$this->current_app_version = config('ninja.app_version');
|
||||||
@ -152,6 +157,7 @@ class CompanyImport implements ShouldQueue
|
|||||||
|
|
||||||
$this->company = Company::where('company_key', $this->company->company_key)->firstOrFail();
|
$this->company = Company::where('company_key', $this->company->company_key)->firstOrFail();
|
||||||
$this->account = $this->company->account;
|
$this->account = $this->company->account;
|
||||||
|
$this->company_owner = $this->company->owner();
|
||||||
|
|
||||||
nlog("Company ID = {$this->company->id}");
|
nlog("Company ID = {$this->company->id}");
|
||||||
nlog("Hash ID = {$this->hash}");
|
nlog("Hash ID = {$this->hash}");
|
||||||
@ -164,17 +170,18 @@ class CompanyImport implements ShouldQueue
|
|||||||
$this->backup_file = json_decode(base64_decode($this->backup_file));
|
$this->backup_file = json_decode(base64_decode($this->backup_file));
|
||||||
|
|
||||||
// nlog($this->backup_file);
|
// nlog($this->backup_file);
|
||||||
|
$this->checkUserCount();
|
||||||
|
|
||||||
if(array_key_exists('import_settings', $this->request_array) && $this->request_array['import_settings'] == 'true') {
|
if(array_key_exists('import_settings', $this->request_array) && $this->request_array['import_settings'] == 'true') {
|
||||||
$this->checkUserCount()->preFlightChecks()->importSettings();
|
|
||||||
|
$this->preFlightChecks()->importSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(array_key_exists('import_data', $this->request_array) && $this->request_array['import_data'] == 'true') {
|
if(array_key_exists('import_data', $this->request_array) && $this->request_array['import_data'] == 'true') {
|
||||||
|
|
||||||
try{
|
try{
|
||||||
|
|
||||||
$this->checkUserCount()
|
$this->preFlightChecks()
|
||||||
->preFlightChecks()
|
|
||||||
->purgeCompanyData()
|
->purgeCompanyData()
|
||||||
->importData();
|
->importData();
|
||||||
|
|
||||||
@ -206,23 +213,21 @@ class CompanyImport implements ShouldQueue
|
|||||||
|
|
||||||
$company_users = $this->company->users;
|
$company_users = $this->company->users;
|
||||||
|
|
||||||
$company_owner = $this->company->owner();
|
|
||||||
|
|
||||||
if($this->company->account->isFreeHostedClient()){
|
|
||||||
|
|
||||||
nlog("This is a free account");
|
nlog("This is a free account");
|
||||||
nlog("Backup user count = ".count($backup_users));
|
nlog("Backup user count = ".count($backup_users));
|
||||||
|
|
||||||
if(count($backup_users) > 1){
|
if(count($backup_users) > 1){
|
||||||
$this->message = 'Only one user can be in the import for a Free Account';
|
// $this->message = 'Only one user can be in the import for a Free Account';
|
||||||
$this->pre_flight_checks_pass = false;
|
// $this->pre_flight_checks_pass = false;
|
||||||
|
$this->force_user_coalesce = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
nlog("backup users email = " . $backup_users[0]->email);
|
nlog("backup users email = " . $backup_users[0]->email);
|
||||||
|
|
||||||
if(count($backup_users) == 1 && $company_owner->email != $backup_users[0]->email) {
|
if(count($backup_users) == 1 && $this->company_owner->email != $backup_users[0]->email) {
|
||||||
$this->message = 'Account emails do not match. Account owner email must match backup user email';
|
// $this->message = 'Account emails do not match. Account owner email must match backup user email';
|
||||||
$this->pre_flight_checks_pass = false;
|
// $this->pre_flight_checks_pass = false;
|
||||||
|
$this->force_user_coalesce = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$backup_users_emails = array_column($backup_users, 'email');
|
$backup_users_emails = array_column($backup_users, 'email');
|
||||||
@ -236,8 +241,9 @@ class CompanyImport implements ShouldQueue
|
|||||||
if($existing_user_count > 1){
|
if($existing_user_count > 1){
|
||||||
|
|
||||||
if($this->account->plan == 'pro'){
|
if($this->account->plan == 'pro'){
|
||||||
$this->message = 'Pro plan is limited to one user, you have multiple users in the backup file';
|
// $this->message = 'Pro plan is limited to one user, you have multiple users in the backup file';
|
||||||
$this->pre_flight_checks_pass = false;
|
// $this->pre_flight_checks_pass = false;
|
||||||
|
$this->force_user_coalesce = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->account->plan == 'enterprise'){
|
if($this->account->plan == 'enterprise'){
|
||||||
@ -268,11 +274,6 @@ class CompanyImport implements ShouldQueue
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
nlog($this->message);
|
|
||||||
nlog($this->pre_flight_checks_pass);
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1217,11 +1218,22 @@ class CompanyImport implements ShouldQueue
|
|||||||
return implode(",", $tmp_arr);
|
return implode(",", $tmp_arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Transform all IDs from old to new
|
||||||
|
*
|
||||||
|
* In the case of users - we need to check if the system
|
||||||
|
* is attempting to migrate resources above their quota,
|
||||||
|
*
|
||||||
|
* ie. > 50 clients or more than 1 user
|
||||||
|
*/
|
||||||
private function transformId(string $resource, ?string $old): ?int
|
private function transformId(string $resource, ?string $old): ?int
|
||||||
{
|
{
|
||||||
if(empty($old))
|
if(empty($old))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
if ($resource == 'users' && $this->force_user_coalesce){
|
||||||
|
return $this->company_owner->id;
|
||||||
|
}
|
||||||
|
|
||||||
if (! array_key_exists($resource, $this->ids)) {
|
if (! array_key_exists($resource, $this->ids)) {
|
||||||
// nlog($this->ids);
|
// nlog($this->ids);
|
||||||
throw new \Exception("Resource {$resource} not available.");
|
throw new \Exception("Resource {$resource} not available.");
|
||||||
|
@ -212,7 +212,7 @@ class Import implements ShouldQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if(Ninja::isHosted() && array_key_exists('ninja_tokens', $data))
|
// if(Ninja::isHosted() && array_key_exists('ninja_tokens', $data))
|
||||||
// $this->processNinjaTokens($data['ninja_tokens']);
|
$this->processNinjaTokens($data['ninja_tokens']);
|
||||||
|
|
||||||
$this->setInitialCompanyLedgerBalances();
|
$this->setInitialCompanyLedgerBalances();
|
||||||
|
|
||||||
@ -1659,8 +1659,10 @@ class Import implements ShouldQueue
|
|||||||
|
|
||||||
private function processNinjaTokens(array $data)
|
private function processNinjaTokens(array $data)
|
||||||
{
|
{
|
||||||
|
nlog("attempting to process Ninja Tokens");
|
||||||
|
|
||||||
if(Ninja::isHosted())
|
if(Ninja::isHosted())
|
||||||
\Modules\Admin\Jobs\Account\NinjaUser::dispatch($data, $this->company);
|
\Modules\Admin\Jobs\Account\NinjaUser::dispatchNow($data, $this->company);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ class PayPalExpressPaymentDriver extends BaseDriver
|
|||||||
|
|
||||||
$message = [
|
$message = [
|
||||||
'server_response' => $response->getMessage(),
|
'server_response' => $response->getMessage(),
|
||||||
'data' => $this->checkout->payment_hash->data,
|
'data' => $this->payment_hash->data,
|
||||||
];
|
];
|
||||||
|
|
||||||
SystemLogger::dispatch(
|
SystemLogger::dispatch(
|
||||||
|
@ -630,7 +630,7 @@ class SubscriptionService
|
|||||||
*/
|
*/
|
||||||
public function triggerWebhook($context)
|
public function triggerWebhook($context)
|
||||||
{
|
{
|
||||||
if (empty($this->subscription->webhook_configuration['post_purchase_url']) || empty($this->subscription->webhook_configuration['post_purchase_rest_method'])) {
|
if (empty($this->subscription->webhook_configuration['post_purchase_url']) || is_null($this->subscription->webhook_configuration['post_purchase_url']) || strlen($this->subscription->webhook_configuration['post_purchase_url']) < 1) {
|
||||||
return ["message" => "Success", "status_code" => 200];
|
return ["message" => "Success", "status_code" => 200];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,6 +99,24 @@ return [
|
|||||||
// ),
|
// ),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'db-ninja-01a' => [
|
||||||
|
'driver' => 'mysql',
|
||||||
|
'host' => env('DB_HOST1', env('DB_HOST', '127.0.0.1')),
|
||||||
|
'database' => env('DB_DATABASE2', env('DB_DATABASE', 'forge')),
|
||||||
|
'username' => env('DB_USERNAME2', env('DB_USERNAME', 'forge')),
|
||||||
|
'password' => env('DB_PASSWORD2', env('DB_PASSWORD', '')),
|
||||||
|
'port' => env('DB_PORT1', env('DB_PORT', '3306')),
|
||||||
|
'charset' => 'utf8mb4',
|
||||||
|
'collation' => 'utf8mb4_unicode_ci',
|
||||||
|
'prefix' => '',
|
||||||
|
'prefix_indexes' => true,
|
||||||
|
'strict' => env('DB_STRICT', false),
|
||||||
|
'engine' => 'InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8',
|
||||||
|
// 'options' => array(
|
||||||
|
// PDO::ATTR_EMULATE_PREPARES => true
|
||||||
|
// ),
|
||||||
|
],
|
||||||
|
|
||||||
'db-ninja-02' => [
|
'db-ninja-02' => [
|
||||||
'driver' => 'mysql',
|
'driver' => 'mysql',
|
||||||
'host' => env('DB_HOST2', env('DB_HOST', '127.0.0.1')),
|
'host' => env('DB_HOST2', env('DB_HOST', '127.0.0.1')),
|
||||||
@ -116,6 +134,24 @@ return [
|
|||||||
// PDO::ATTR_EMULATE_PREPARES => true
|
// PDO::ATTR_EMULATE_PREPARES => true
|
||||||
// ),
|
// ),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'db-ninja-02a' => [
|
||||||
|
'driver' => 'mysql',
|
||||||
|
'host' => env('DB_HOST2', env('DB_HOST', '127.0.0.1')),
|
||||||
|
'database' => env('DB_DATABASE1', env('DB_DATABASE', 'forge')),
|
||||||
|
'username' => env('DB_USERNAME1', env('DB_USERNAME', 'forge')),
|
||||||
|
'password' => env('DB_PASSWORD1', env('DB_PASSWORD', '')),
|
||||||
|
'port' => env('DB_PORT2', env('DB_PORT', '3306')),
|
||||||
|
'charset' => 'utf8mb4',
|
||||||
|
'collation' => 'utf8mb4_unicode_ci',
|
||||||
|
'prefix' => '',
|
||||||
|
'prefix_indexes' => true,
|
||||||
|
'strict' => env('DB_STRICT', false),
|
||||||
|
'engine' => 'InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8',
|
||||||
|
// 'options' => array(
|
||||||
|
// PDO::ATTR_EMULATE_PREPARES => true
|
||||||
|
// ),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -14,8 +14,8 @@ return [
|
|||||||
'require_https' => env('REQUIRE_HTTPS', true),
|
'require_https' => env('REQUIRE_HTTPS', true),
|
||||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||||
'app_version' => '5.1.72',
|
'app_version' => '5.1.74',
|
||||||
'app_tag' => '5.1.72-release',
|
'app_tag' => '5.1.74-release',
|
||||||
'minimum_client_version' => '5.0.16',
|
'minimum_client_version' => '5.0.16',
|
||||||
'terms_version' => '1.0.1',
|
'terms_version' => '1.0.1',
|
||||||
'api_secret' => env('API_SECRET', ''),
|
'api_secret' => env('API_SECRET', ''),
|
||||||
|
Loading…
Reference in New Issue
Block a user