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

Merge pull request #5597 from turbo124/v5-develop

Fixes for migration
This commit is contained in:
David Bomba 2021-05-04 17:00:45 +10:00 committed by GitHub
commit 4abaa71b01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 436 additions and 72 deletions

View File

@ -0,0 +1,120 @@
<?php
namespace App\Console\Commands;
use App\Models\Company;
use App\Models\User;
use App\Utils\CurlUtils;
use Illuminate\Console\Command;
class MobileLocalization extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'ninja:mobile-localization {--type=}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Generate mobile localization resources';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$type = strtolower($this->option('type'));
switch ($type) {
case 'laravel':
$this->laravelResources();
break;
default:
$this->flutterResources();
break;
}
}
private function laravelResources()
{
$resources = $this->getResources();
foreach ($resources as $key => $val) {
$transKey = "texts.{$key}";
if (trans($transKey) == $transKey) {
echo "'$key' => '$val',\n";
}
}
}
private function flutterResources()
{
$languages = cache('languages');
$resources = $this->getResources();
foreach ($languages as $language) {
if ($language->locale == 'en') {
continue;
}
echo "'{$language->locale}': {\n";
foreach ($resources as $key => $val) {
$text = trim(addslashes(trans("texts.{$key}", [], $language->locale)));
if (substr($text, 0, 6) == 'texts.') {
$text = $resources->$key;
}
$text = str_replace(array('<b>', '</b>'), '', $text);
$text = str_replace(array('<i>', '</i>'), '', $text);
$text = str_replace(array('<strong>', '</strong>'), '', $text);
echo "'$key': '$text',\n";
}
echo "},\n";
}
}
private function getResources()
{
$url = 'https://raw.githubusercontent.com/invoiceninja/flutter-client/develop/lib/utils/i18n.dart';
$data = CurlUtils::get($url);
$start = strpos($data, 'do not remove comment') + 25;
$end = strpos($data, '},', $start);
$data = substr($data, $start, $end - $start - 5);
$data = str_replace("\n", "", $data);
$data = str_replace("\"", "\'", $data);
$data = str_replace("'", "\"", $data);
return json_decode('{' . rtrim($data, ',') . '}');
}
protected function getOptions()
{
return [
['type', null, InputOption::VALUE_OPTIONAL, 'Type', null],
];
}
}

View File

@ -0,0 +1,77 @@
<?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\DataMapper\Analytics;
class EmailBounce
{
/**
* The type of Sample.
*
* Monotonically incrementing counter
*
* - counter
*
* @var string
*/
public $type = 'mixed_metric';
/**
* The name of the counter.
* @var string
*/
public $name = 'job.bounce.email';
/**
* The datetime of the counter measurement.
*
* date("Y-m-d H:i:s")
*
* @var DateTime
*/
public $datetime;
/**
* The Class failure name
* set to 0.
*
* @var string
*/
public $string_metric5 = 'tag';
/**
* The exception string
* set to 0.
*
* @var string
*/
public $string_metric6 = 'from';
/**
* Company Key
* @var string
*/
public $string_metric7 = 'messageid';
/**
* The counter
* set to 1.
*
* @var string
*/
public $int_metric1 = 1;
public function __construct($string_metric5,$string_metric6,$string_metric7) {
$this->string_metric5 = $string_metric5;
$this->string_metric6 = $string_metric6;
$this->string_metric7 = $string_metric7;
}
}

View File

@ -0,0 +1,77 @@
<?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\DataMapper\Analytics;
class EmailSpam
{
/**
* The type of Sample.
*
* Monotonically incrementing counter
*
* - counter
*
* @var string
*/
public $type = 'mixed_metric';
/**
* The name of the counter.
* @var string
*/
public $name = 'job.spam.email';
/**
* The datetime of the counter measurement.
*
* date("Y-m-d H:i:s")
*
* @var DateTime
*/
public $datetime;
/**
* The Class failure name
* set to 0.
*
* @var string
*/
public $string_metric5 = 'tag';
/**
* The exception string
* set to 0.
*
* @var string
*/
public $string_metric6 = 'from';
/**
* Company Key
* @var string
*/
public $string_metric7 = 'messageid';
/**
* The counter
* set to 1.
*
* @var string
*/
public $int_metric1 = 1;
public function __construct($string_metric5,$string_metric6,$string_metric7) {
$this->string_metric5 = $string_metric5;
$this->string_metric6 = $string_metric6;
$this->string_metric7 = $string_metric7;
}
}

View File

@ -18,6 +18,7 @@ use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
use App\Jobs\Util\StartMigration;
use App\Mail\ExistingMigration;
use App\Mail\Migration\MaxCompanies;
use App\Models\Company;
use App\Models\CompanyToken;
use Illuminate\Foundation\Bus\DispatchesJobs;
@ -231,19 +232,51 @@ class MigrationController extends BaseController
nlog($request->all());
}
try {
return response()->json([
'_id' => Str::uuid(),
'method' => config('queue.default'),
'started_at' => now(),
], 200);
} finally {
// Controller logic here
foreach ($companies as $company) {
$is_valid = $request->file($company->company_index)->isValid();
if (!$is_valid) {
// We might want to send user something's wrong with migration or nope?
continue;
}
$user = auth()->user();
$company_count = $user->account->companies()->count();
// Look for possible existing company (based on company keys).
$existing_company = Company::whereRaw('BINARY `company_key` = ?', [$company->company_key])->first();
if(!$existing_company && $company_count >=10) {
$nmo = new NinjaMailerObject;
$nmo->mailable = new MaxCompanies($user->account->companies()->first());
$nmo->company = $user->account->companies()->first();
$nmo->settings = $user->account->companies()->first()->settings;
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
return;
}
elseif($existing_company && $company_count > 10 ){
$nmo = new NinjaMailerObject;
$nmo->mailable = new MaxCompanies($user->account->companies()->first());
$nmo->company = $user->account->companies()->first();
$nmo->settings = $user->account->companies()->first()->settings;
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
return;
}
$checks = [
'existing_company' => $existing_company ? (bool)1 : false,
'force' => property_exists($company, 'force') ? (bool) $company->force : false,
@ -254,11 +287,11 @@ class MigrationController extends BaseController
nlog('Migrating: Existing company without force. (CASE_01)');
$nmo = new NinjaMailerObject;
$nmo->mailable = new ExistingMigration();
$nmo->company = $existing_company;
$nmo->settings = $existing_company->settings;
$nmo->mailable = new ExistingMigration($existing_company);
$nmo->company = $user->account->companies()->first();
$nmo->settings = $user->account->companies()->first();
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
return response()->json([
@ -355,10 +388,7 @@ class MigrationController extends BaseController
// }
}
return response()->json([
'_id' => Str::uuid(),
'method' => config('queue.default'),
'started_at' => now(),
], 200);
}
}
}

View File

@ -11,6 +11,8 @@
namespace App\Http\Controllers;
use App\DataMapper\Analytics\EmailBounce;
use App\DataMapper\Analytics\EmailSpam;
use App\Jobs\Util\SystemLogger;
use App\Libraries\MultiDB;
use App\Models\CreditInvitation;
@ -19,6 +21,7 @@ use App\Models\QuoteInvitation;
use App\Models\RecurringInvoiceInvitation;
use App\Models\SystemLog;
use Illuminate\Http\Request;
use Turbo124\Beacon\Facades\LightLogs;
/**
* Class PostMarkController.
@ -71,8 +74,7 @@ class PostMarkController extends BaseController
if($request->header('X-API-SECURITY') && $request->header('X-API-SECURITY') == config('postmark.secret'))
{
nlog($request->all());
// nlog($request->all());
MultiDB::findAndSetDbByCompanyKey($request->input('Tag'));
@ -157,6 +159,14 @@ class PostMarkController extends BaseController
$this->invitation->email_status = 'bounced';
$this->invitation->save();
$bounce = new EmailBounce(
$request->input('Tag'),
$request->input('From'),
$request->input('MessageID')
);
LightLogs::create($bounce)->batch();
SystemLogger::dispatch($request->all(), SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_BOUNCED, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client);
}
@ -191,6 +201,14 @@ class PostMarkController extends BaseController
$this->invitation->email_status = 'spam';
$this->invitation->save();
$spam = new EmailSpam(
$request->input('Tag'),
$request->input('From'),
$request->input('MessageID')
);
LightLogs::create($bounce)->batch();
SystemLogger::dispatch($request->all(), SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_SPAM_COMPLAINT, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client);
}

View File

@ -10,14 +10,22 @@ class ExistingMigration extends Mailable
{
// use Queueable, SerializesModels;
public $company;
public $settings;
public $logo;
public $company_name;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct()
public function __construct($company)
{
//
$this->company = $company;
}
/**
@ -27,8 +35,11 @@ class ExistingMigration extends Mailable
*/
public function build()
{
return $this->from(config('mail.from.address'), config('mail.from.name'))
$this->settings = $this->company->settings;
$this->logo = $this->company->present()->logo();
$this->company_name = $this->company->present()->name();
return $this->from(config('mail.from.address'), config('mail.from.name'))
->view('email.migration.existing');
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace App\Mail\Migration;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class MaxCompanies extends Mailable
{
// use Queueable, SerializesModels;
public $company;
public $settings;
public $logo;
public $title;
public $message;
public $whitelabel;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct($company)
{
$this->company = $company;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
$this->settings = $this->company->settings;
$this->logo = $this->company->present()->logo();
$this->title = ctrans('texts.max_companies');
$this->message = ctrans('texts.max_companies_desc');
$this->whitelabel = $this->company->account->isPaid();
return $this->from(config('mail.from.address'), config('mail.from.name'))
->view('email.migration.max_companies');
}
}

View File

@ -225,7 +225,7 @@ class CompanyGateway extends BaseModel
{
$config = $this->getConfig();
if ($this->gateway->provider == 'Stripe' && strpos($config->publishableKey, 'test')) {
if ($this->gateway->provider == 'Stripe' && property_exists($config, 'publishableKey') && strpos($config->publishableKey, 'test')) {
return true;
}

View File

@ -107,35 +107,7 @@ class InvoiceMigrationRepository extends BaseRepository
InvoiceInvitation::reguard();
RecurringInvoiceInvitation::reguard();
/*
if (isset($data['invitations'])) {
$invitations = collect($data['invitations']);
$model->invitations->pluck('key')->diff($invitations->pluck('key'))->each(function ($invitation) use ($resource) {
$this->getInvitation($invitation, $resource)->delete();
});
foreach ($data['invitations'] as $invitation) {
//if no invitations are present - create one.
if (! $this->getInvitation($invitation, $resource)) {
if (isset($invitation['id'])) {
unset($invitation['id']);
}
//make sure we are creating an invite for a contact who belongs to the client only!
$contact = ClientContact::find($invitation['client_contact_id']);
if ($contact && $model->client_id == $contact->client_id) {
$new_invitation = $invitation_factory_class::create($model->company_id, $model->user_id);
$new_invitation->{$lcfirst_resource_id} = $model->id;
$new_invitation->client_contact_id = $contact->id;
$new_invitation->save();
}
}
}
}
*/
$model->load('invitations');
/* If no invitations have been created, this is our fail safe to maintain state*/
@ -152,8 +124,6 @@ class InvoiceMigrationRepository extends BaseRepository
if ($class->name == Invoice::class || $class->name == RecurringInvoice::class) {
if (($state['finished_amount'] != $state['starting_amount']) && ($model->status_id != Invoice::STATUS_DRAFT)) {
// $model->ledger()->updateInvoiceBalance(($state['finished_amount'] - $state['starting_amount']));
// $model->client->service()->updateBalance(($state['finished_amount'] - $state['starting_amount']))->save();
}
if (! $model->design_id) {
@ -162,7 +132,7 @@ class InvoiceMigrationRepository extends BaseRepository
if ($model->company->update_products) {
UpdateOrCreateProduct::dispatchNow($model->line_items, $model, $model->company);
//UpdateOrCreateProduct::dispatchNow($model->line_items, $model, $model->company);
}
}

View File

@ -4235,6 +4235,11 @@ $LANG = array(
'notification_quote_created_subject' => 'Quote :invoice was created for :client',
'notification_credit_created_subject' => 'Credit :invoice was created to :client',
'notification_credit_created_subject' => 'Credit :invoice was created for :client',
'max_companies' => 'Maximum companies migrated',
'max_companies_desc' => 'You have reached your maximum number of companies. Delete existing companies to migrate new ones.',
'migration_already_completed' => 'Company already migrated',
'migration_already_completed_desc' => 'Looks like you already migrated <b> :company_name </b>to the V5 version of the Invoice Ninja. In case you want to start over, you can force migrate to wipe existing data.',
);
return $LANG;

View File

@ -1,31 +1,18 @@
@component('email.template.master', ['design' => 'light', 'settings' => $settings])
@slot('header')
@component('email.components.header')
Migration already completed
@endcomponent
@endslot
@slot('header')
@include('email.components.header', ['logo' => $logo])
@endslot
@slot('greeting')
Hello,
@endslot
<h2>{{ctrans('texts.migration_already_completed')}}</h2>
Looks like you already migrated your data to V2 version of the Invoice Ninja. In case you want to start over, you can 'force' migrate to wipe existing data.
@component('email.components.button', ['url' => url('/')])
Visit portal
@endcomponent
@slot('signature')
Thank you, <br>
Invoice Ninja
@endslot
@slot('footer')
@component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '&copy; InvoiceNinja'])
For any info, please visit InvoiceNinja.
@endcomponent
@endslot
<p>{{ctrans('texts.migration_already_completed_desc', ['company_name' => $company_name])}}</p>
@if(isset($whitelabel) && !$whitelabel)
@slot('footer')
@component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '&copy; InvoiceNinja'])
For any info, please visit InvoiceNinja.
@endcomponent
@endslot
@endif
@endcomponent

View File

@ -0,0 +1,18 @@
@component('email.template.master', ['design' => 'light', 'settings' => $settings])
@slot('header')
@include('email.components.header', ['logo' => $logo])
@endslot
<h2>{{ctrans('texts.max_companies')}}</h2>
<p>{{ctrans('texts.max_companies_desc')}}</p>
@if(isset($whitelabel) && !$whitelabel)
@slot('footer')
@component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '&copy; InvoiceNinja'])
For any info, please visit InvoiceNinja.
@endcomponent
@endslot
@endif
@endcomponent