mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-10-30 20:43:52 -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,6 +149,7 @@ 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; | ||||||
| 
 | 
 | ||||||
| @ -406,6 +407,8 @@ 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