mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-08 01:04:36 -04:00
Merge pull request #5699 from turbo124/v5-develop
Fixes for download export button
This commit is contained in:
commit
1ebdb96b51
10
app/Exceptions/NonExistingBackupFile.php
Normal file
10
app/Exceptions/NonExistingBackupFile.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class NonExistingBackupFile extends Exception
|
||||||
|
{
|
||||||
|
// ..
|
||||||
|
}
|
@ -366,13 +366,92 @@ class BaseController extends Controller
|
|||||||
return $this->response($this->manager->createData($resource)->toArray());
|
return $this->response($this->manager->createData($resource)->toArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function miniLoadResponse($query)
|
||||||
|
{
|
||||||
|
$user = auth()->user();
|
||||||
|
|
||||||
|
|
||||||
|
$this->serializer = request()->input('serializer') ?: EntityTransformer::API_SERIALIZER_ARRAY;
|
||||||
|
|
||||||
|
if ($this->serializer === EntityTransformer::API_SERIALIZER_JSON) {
|
||||||
|
$this->manager->setSerializer(new JsonApiSerializer());
|
||||||
|
} else {
|
||||||
|
$this->manager->setSerializer(new ArraySerializer());
|
||||||
|
}
|
||||||
|
|
||||||
|
$transformer = new $this->entity_transformer($this->serializer);
|
||||||
|
$created_at = request()->has('created_at') ? request()->input('created_at') : 0;
|
||||||
|
|
||||||
|
$created_at = date('Y-m-d H:i:s', $created_at);
|
||||||
|
|
||||||
|
$query->with(
|
||||||
|
[
|
||||||
|
'company' => function ($query) use ($created_at, $user) {
|
||||||
|
$query->whereNotNull('created_at')->with('documents');
|
||||||
|
},
|
||||||
|
'company.designs'=> function ($query) use ($created_at, $user) {
|
||||||
|
$query->where('created_at', '>=', $created_at)->with('company');
|
||||||
|
|
||||||
|
if(!$user->isAdmin())
|
||||||
|
$query->where('designs.user_id', $user->id);
|
||||||
|
},
|
||||||
|
'company.documents'=> function ($query) use ($created_at, $user) {
|
||||||
|
$query->where('created_at', '>=', $created_at);
|
||||||
|
},
|
||||||
|
'company.groups' => function ($query) use ($created_at, $user) {
|
||||||
|
$query->where('created_at', '>=', $created_at);
|
||||||
|
|
||||||
|
if(!$user->isAdmin())
|
||||||
|
$query->where('group_settings.user_id', $user->id);
|
||||||
|
},
|
||||||
|
'company.payment_terms'=> function ($query) use ($created_at, $user) {
|
||||||
|
$query->where('created_at', '>=', $created_at);
|
||||||
|
|
||||||
|
if(!$user->isAdmin())
|
||||||
|
$query->where('payment_terms.user_id', $user->id);
|
||||||
|
|
||||||
|
},
|
||||||
|
'company.tax_rates' => function ($query) use ($created_at, $user) {
|
||||||
|
$query->where('created_at', '>=', $created_at);
|
||||||
|
|
||||||
|
if(!$user->isAdmin())
|
||||||
|
$query->where('tax_rates.user_id', $user->id);
|
||||||
|
|
||||||
|
},
|
||||||
|
'company.activities'=> function ($query) use($user) {
|
||||||
|
|
||||||
|
if(!$user->isAdmin())
|
||||||
|
$query->where('activities.user_id', $user->id);
|
||||||
|
|
||||||
|
}
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($query instanceof Builder) {
|
||||||
|
$limit = request()->input('per_page', 20);
|
||||||
|
|
||||||
|
$paginator = $query->paginate($limit);
|
||||||
|
$query = $paginator->getCollection();
|
||||||
|
$resource = new Collection($query, $transformer, $this->entity_type);
|
||||||
|
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||||
|
} else {
|
||||||
|
$resource = new Collection($query, $transformer, $this->entity_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->response($this->manager->createData($resource)->toArray());
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected function timeConstrainedResponse($query)
|
protected function timeConstrainedResponse($query)
|
||||||
{
|
{
|
||||||
|
|
||||||
$user = auth()->user();
|
$user = auth()->user();
|
||||||
|
|
||||||
if ($user->getCompany()->is_large)
|
if ($user->getCompany()->is_large){
|
||||||
$this->manager->parseIncludes($this->mini_load);
|
$this->manager->parseIncludes($this->mini_load);
|
||||||
|
return $this->miniLoadResponse($query);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
$this->manager->parseIncludes($this->first_load);
|
$this->manager->parseIncludes($this->first_load);
|
||||||
|
|
||||||
|
@ -24,12 +24,12 @@ class ContactHashLoginController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function login(string $contact_key)
|
public function login(string $contact_key)
|
||||||
{
|
{
|
||||||
return redirect('/client/login');
|
return redirect('/client/invoices');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function magicLink(string $magic_link)
|
public function magicLink(string $magic_link)
|
||||||
{
|
{
|
||||||
return redirect('/client/login');
|
return redirect('/client/invoices');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function errorPage()
|
public function errorPage()
|
||||||
|
@ -42,7 +42,7 @@ class ContactKeyLogin
|
|||||||
if (MultiDB::findAndSetDbByContactKey($request->segment(3))) {
|
if (MultiDB::findAndSetDbByContactKey($request->segment(3))) {
|
||||||
|
|
||||||
if($client_contact = ClientContact::where('contact_key', $request->segment(3))->first()){
|
if($client_contact = ClientContact::where('contact_key', $request->segment(3))->first()){
|
||||||
auth()->guard('contact')->login($client_contact, true);
|
Auth::guard('contact')->login($client_contact, true);
|
||||||
return redirect()->to('client/dashboard');
|
return redirect()->to('client/dashboard');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ class CompanyExport implements ShouldQueue
|
|||||||
*
|
*
|
||||||
* @return CompanyToken|null
|
* @return CompanyToken|null
|
||||||
*/
|
*/
|
||||||
public function handle() : void
|
public function handle()
|
||||||
{
|
{
|
||||||
|
|
||||||
MultiDB::setDb($this->company->db);
|
MultiDB::setDb($this->company->db);
|
||||||
@ -149,7 +149,8 @@ class CompanyExport implements ShouldQueue
|
|||||||
$this->export_data['company_gateways'] = $this->company->company_gateways->map(function ($company_gateway){
|
$this->export_data['company_gateways'] = $this->company->company_gateways->map(function ($company_gateway){
|
||||||
|
|
||||||
$company_gateway = $this->transformArrayOfKeys($company_gateway, ['company_id', 'user_id']);
|
$company_gateway = $this->transformArrayOfKeys($company_gateway, ['company_id', 'user_id']);
|
||||||
|
$company_gateway->config = decrypt($company_gateway->config);
|
||||||
|
|
||||||
return $company_gateway;
|
return $company_gateway;
|
||||||
|
|
||||||
})->toArray();
|
})->toArray();
|
||||||
@ -405,7 +406,9 @@ class CompanyExport implements ShouldQueue
|
|||||||
|
|
||||||
//write to tmp and email to owner();
|
//write to tmp and email to owner();
|
||||||
|
|
||||||
$this->zipAndSend();
|
$this->zipAndSend();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function transformBasicEntities($model)
|
private function transformBasicEntities($model)
|
||||||
|
127
app/Jobs/Company/CompanyImport.php
Normal file
127
app/Jobs/Company/CompanyImport.php
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<?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\Jobs\Company;
|
||||||
|
|
||||||
|
use App\Exceptions\NonExistingMigrationFile;
|
||||||
|
use App\Jobs\Mail\NinjaMailerJob;
|
||||||
|
use App\Jobs\Mail\NinjaMailerObject;
|
||||||
|
use App\Jobs\Util\UnlinkFile;
|
||||||
|
use App\Libraries\MultiDB;
|
||||||
|
use App\Mail\DownloadBackup;
|
||||||
|
use App\Mail\DownloadInvoices;
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Models\CreditInvitation;
|
||||||
|
use App\Models\InvoiceInvitation;
|
||||||
|
use App\Models\QuoteInvitation;
|
||||||
|
use App\Models\RecurringInvoice;
|
||||||
|
use App\Models\RecurringInvoiceInvitation;
|
||||||
|
use App\Models\User;
|
||||||
|
use App\Models\VendorContact;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use ZipArchive;
|
||||||
|
use ZipStream\Option\Archive;
|
||||||
|
use ZipStream\ZipStream;
|
||||||
|
|
||||||
|
class CompanyImport implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, MakesHash;
|
||||||
|
|
||||||
|
public $company;
|
||||||
|
|
||||||
|
public $file_path;
|
||||||
|
|
||||||
|
private $backup_file;
|
||||||
|
|
||||||
|
public $import_company;
|
||||||
|
|
||||||
|
private $options = '';
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @param Company $company
|
||||||
|
* @param User $user
|
||||||
|
* @param string $custom_token_name
|
||||||
|
*/
|
||||||
|
public function __construct(Company $company, string $file_path, array $options)
|
||||||
|
{
|
||||||
|
$this->company = $company;
|
||||||
|
$this->file_path = $file_path;
|
||||||
|
$this->options = $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
MultiDB::setDb($this->company->db);
|
||||||
|
|
||||||
|
$this->company =Company::where('company_key', $this->company->company_key)->firstOrFail();
|
||||||
|
|
||||||
|
$this->unzipFile()
|
||||||
|
->preFlightChecks();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//check if this is a complete company import OR if it is selective
|
||||||
|
/*
|
||||||
|
Company and settings only
|
||||||
|
Data
|
||||||
|
*/
|
||||||
|
|
||||||
|
private function preFlightChecks()
|
||||||
|
{
|
||||||
|
//check the file version and perform any necessary adjustments to the file in order to proceed - needed when we change schema
|
||||||
|
//
|
||||||
|
$app_version = $this->backup_file->app_version;
|
||||||
|
|
||||||
|
nlog($app_version);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function unzipFile()
|
||||||
|
{
|
||||||
|
$zip = new ZipArchive();
|
||||||
|
$archive = $zip->open(public_path("storage/backups/{$this->file_path}"));
|
||||||
|
$filename = pathinfo($this->filepath, PATHINFO_FILENAME);
|
||||||
|
$zip->extractTo(public_path("storage/backups/{$filename}"));
|
||||||
|
$zip->close();
|
||||||
|
$file_location = public_path("storage/backups/$filename/backup.json");
|
||||||
|
|
||||||
|
if (! file_exists($file_location)) {
|
||||||
|
throw new NonExistingMigrationFile('Backup file does not exist, or it is corrupted.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->backup_file = json_decode(file_get_contents($file_location));
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function importCompany()
|
||||||
|
{
|
||||||
|
|
||||||
|
//$this->import_company = ..
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function importData()
|
||||||
|
{
|
||||||
|
// $this->import_company = Company::where('company_key', $this->company->company_key)->firstOrFail();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
@component('email.template.master', ['design' => 'light', 'settings' =>$settings])
|
@component('email.template.master', ['design' => 'light', 'settings' =>$settings])
|
||||||
|
|
||||||
@slot('header')
|
@slot('header')
|
||||||
@component('email.components.header', ['p' => '', 'logo' => $url])
|
@component('email.components.header', ['p' => '', 'logo' => $logo])
|
||||||
@lang('texts.download')
|
@lang('texts.download')
|
||||||
@endcomponent
|
@endcomponent
|
||||||
|
|
||||||
@ -12,6 +12,11 @@
|
|||||||
|
|
||||||
@lang('texts.download_timeframe')
|
@lang('texts.download_timeframe')
|
||||||
|
|
||||||
|
|
||||||
|
@component('email.components.button', ['url' => $url])
|
||||||
|
@lang('texts.download')
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
@slot('signature')
|
@slot('signature')
|
||||||
InvoiceNinja (contact@invoiceninja.com)
|
InvoiceNinja (contact@invoiceninja.com)
|
||||||
@endslot
|
@endslot
|
||||||
|
@ -44,8 +44,8 @@ class ExportCompanyTest extends TestCase
|
|||||||
|
|
||||||
public function testCompanyExport()
|
public function testCompanyExport()
|
||||||
{
|
{
|
||||||
CompanyExport::dispatchNow($this->company, $this->company->users->first());
|
$res = CompanyExport::dispatchNow($this->company, $this->company->users->first());
|
||||||
|
|
||||||
$this->assertTrue(true);
|
$this->assertTrue($res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
56
tests/Feature/Import/ImportCompanyTest.php
Normal file
56
tests/Feature/Import/ImportCompanyTest.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?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 Tests\Feature\Import;
|
||||||
|
|
||||||
|
use App\Jobs\Import\CSVImport;
|
||||||
|
use App\Models\Client;
|
||||||
|
use App\Models\Expense;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\Payment;
|
||||||
|
use App\Models\Product;
|
||||||
|
use App\Models\Vendor;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use League\Csv\Reader;
|
||||||
|
use League\Csv\Statement;
|
||||||
|
use Tests\MockAccountData;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class ImportCompanyTest extends TestCase
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
|
public function setUp() :void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->withoutMiddleware(
|
||||||
|
ThrottleRequests::class
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
$this->withoutExceptionHandling();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testBackupJsonRead()
|
||||||
|
{
|
||||||
|
$backup_json_file = base_path().'/tests/Feature/Import/backup.json';
|
||||||
|
|
||||||
|
$this->assertTrue(is_array(json_decode(file_get_contents($backup_json_file),1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1
tests/Feature/Import/backup.json
Normal file
1
tests/Feature/Import/backup.json
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user