diff --git a/app/Console/Commands/BackupUpdate.php b/app/Console/Commands/BackupUpdate.php new file mode 100644 index 000000000000..08afc832475b --- /dev/null +++ b/app/Console/Commands/BackupUpdate.php @@ -0,0 +1,91 @@ +handleOnDb(); + } else { + + //multiDB environment, need to + foreach (MultiDB::$dbs as $db) { + MultiDB::setDB($db); + + $this->handleOnDb(); + } + + MultiDB::setDB($current_db); + + } + + + } + + private function handleOnDb() + { + + Backup::whereHas('activity')->whereNotNull('html_backup')->cursor()->each(function($backup){ + + if($backup->activity->client()->exists()){ + + $client = $backup->activity->client; + $backup->storeRemotely($backup->html_backup, $client); + + } + + }); + + } +} diff --git a/app/Http/Controllers/ActivityController.php b/app/Http/Controllers/ActivityController.php index 9b1bf584d66c..e6bf5ad711e6 100644 --- a/app/Http/Controllers/ActivityController.php +++ b/app/Http/Controllers/ActivityController.php @@ -20,6 +20,7 @@ use App\Utils\Traits\Pdf\PdfMaker; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Http\Response; +use Illuminate\Support\Facades\Storage; use Symfony\Component\HttpFoundation\StreamedResponse; use stdClass; @@ -136,19 +137,33 @@ class ActivityController extends BaseController public function downloadHistoricalEntity(DownloadHistoricalEntityRequest $request, Activity $activity) { $backup = $activity->backup; + $html_backup = ''; - if (! $backup || ! $backup->html_backup) { + /* Refactor 20-10-2021 + * + * We have moved the backups out of the database and into object storage. + * In order to handle edge cases, we still check for the database backup + * in case the file no longer exists + */ + + if($backup && $backup->filename && Storage::disk(config('filesystems.default'))->exists($backup->filename)){ //disk + $html_backup = file_get_contents(Storage::disk(config('filesystems.default'))->path($backup->filename)); + } + elseif($backup && $backup->html_backup){ //db + $html_backup = $backup->html_backup; + } + elseif (! $backup || ! $backup->html_backup) { //failed return response()->json(['message'=> ctrans('texts.no_backup_exists'), 'errors' => new stdClass], 404); } if (config('ninja.phantomjs_pdf_generation') || config('ninja.pdf_generator') == 'phantom') { - $pdf = (new Phantom)->convertHtmlToPdf($backup->html_backup); + $pdf = (new Phantom)->convertHtmlToPdf($html_backup); } elseif(config('ninja.invoiceninja_hosted_pdf_generation') || config('ninja.pdf_generator') == 'hosted_ninja'){ - $pdf = (new NinjaPdf())->build($backup->html_backup); + $pdf = (new NinjaPdf())->build($html_backup); } else { - $pdf = $this->makePdf(null, null, $backup->html_backup); + $pdf = $this->makePdf(null, null, $html_backup); } if (isset($activity->invoice_id)) { diff --git a/app/Http/Requests/Invoice/StoreInvoiceRequest.php b/app/Http/Requests/Invoice/StoreInvoiceRequest.php index 824a8e6d9b01..82436912eaad 100644 --- a/app/Http/Requests/Invoice/StoreInvoiceRequest.php +++ b/app/Http/Requests/Invoice/StoreInvoiceRequest.php @@ -70,6 +70,13 @@ class StoreInvoiceRequest extends Request $input['amount'] = 0; $input['balance'] = 0; + if(array_key_exists('tax_rate1', $input) && is_null($input['tax_rate1'])) + $input['tax_rate1'] = 0; + if(array_key_exists('tax_rate2', $input) && is_null($input['tax_rate2'])) + $input['tax_rate2'] = 0; + if(array_key_exists('tax_rate3', $input) && is_null($input['tax_rate3'])) + $input['tax_rate3'] = 0; + $this->replace($input); } } diff --git a/app/Models/Backup.php b/app/Models/Backup.php index 403837108c8f..72fa770ca6e6 100644 --- a/app/Models/Backup.php +++ b/app/Models/Backup.php @@ -11,6 +11,9 @@ namespace App\Models; +use App\Models\Client; +use Illuminate\Support\Facades\Storage; + class Backup extends BaseModel { public function getEntityType() @@ -22,4 +25,26 @@ class Backup extends BaseModel { return $this->belongsTo(Activity::class); } + + public function storeRemotely(string $html, Client $client) + { + + if(strlen($html) == 0) + return; + + $path = $client->backup_path() . "/"; + $filename = now()->format('Y_m_d'). "_" . md5(time()) . ".html"; + $file_path = $path . $filename; + + Storage::disk(config('filesystems.default'))->makeDirectory($path, 0775); + + Storage::disk(config('filesystems.default'))->put($file_path, $html); + + if(Storage::disk(config('filesystems.default'))->exists($file_path)){ + $this->html_backup = ''; + $this->filename = $file_path; + $this->save(); + } + + } } diff --git a/app/Models/Client.php b/app/Models/Client.php index 1a739f288604..483038a589fc 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -717,6 +717,12 @@ class Client extends BaseModel implements HasLocalePreference })->first()->locale; } + public function backup_path() + { + return $this->company->company_key.'/'.$this->client_hash.'/backups'; + } + + public function invoice_filepath($invitation) { $contact_key = $invitation->contact->contact_key; diff --git a/app/Repositories/ActivityRepository.php b/app/Repositories/ActivityRepository.php index c2d0e946a0c9..6da7e24d398d 100644 --- a/app/Repositories/ActivityRepository.php +++ b/app/Repositories/ActivityRepository.php @@ -73,24 +73,25 @@ class ActivityRepository extends BaseRepository if ($entity instanceof User || $entity->company->is_disabled) return; - - $backup = new Backup(); - if (get_class($entity) == Invoice::class || get_class($entity) == Quote::class || get_class($entity) == Credit::class || get_class($entity) == RecurringInvoice::class ) { - + + $backup = new Backup(); $entity->load('client'); $contact = $entity->client->primary_contact()->first(); $backup->html_backup = $this->generateHtml($entity); $backup->amount = $entity->amount; + $backup->activity_id = $activity->id; + $backup->json_backup = ''; + $backup->save(); + + $backup->storeRemotely($this->generateHtml($entity), $entity->client); } - $backup->activity_id = $activity->id; - $backup->json_backup = ''; - $backup->save(); + } public function getTokenId(array $event_vars) @@ -126,7 +127,7 @@ class ActivityRepository extends BaseRepository if(!$entity->invitations()->exists() || !$design){ nlog("No invitations for entity {$entity->id} - {$entity->number}"); - return; + return ''; } $entity->load('client.company', 'invitations'); diff --git a/database/migrations/2021_10_20_005529_add_filename_to_backups_table.php b/database/migrations/2021_10_20_005529_add_filename_to_backups_table.php new file mode 100644 index 000000000000..b73264237a29 --- /dev/null +++ b/database/migrations/2021_10_20_005529_add_filename_to_backups_table.php @@ -0,0 +1,29 @@ +text('filename')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + } +}