1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-09-19 16:01:34 +02:00

Display documents and zip download on client invoice page

This commit is contained in:
Joshua Dwire 2016-03-23 22:41:19 -04:00
parent 2a7e8cb4b7
commit e6056104bd
8 changed files with 169 additions and 8 deletions

View File

@ -19,6 +19,8 @@ use App\Ninja\Repositories\ActivityRepository;
use App\Events\InvoiceInvitationWasViewed;
use App\Events\QuoteInvitationWasViewed;
use App\Services\PaymentService;
use League\Flysystem\Filesystem;
use League\Flysystem\ZipArchive\ZipArchiveAdapter;
class PublicClientController extends BaseController
{
@ -135,6 +137,10 @@ class PublicClientController extends BaseController
'checkoutComDebug' => $checkoutComDebug,
'phantomjs' => Input::has('phantomjs'),
);
if($account->isPro() && $this->canCreateInvoiceDocsZip($invoice)){
$data['documentsZipURL'] = URL::to("client/documents/{$invitation->invitation_key}");
}
return View::make('invoices.view', $data);
}
@ -375,9 +381,7 @@ class PublicClientController extends BaseController
return $invitation;
}
public function getDocumentVFSJS($publicId, $name){
if (!$invitation = $this->getInvitation()) {
return $this->returnError();
@ -415,6 +419,101 @@ class PublicClientController extends BaseController
return $response;
}
protected function canCreateZip(){
return function_exists('gmp_init');
}
protected function canCreateInvoiceDocsZip($invoice){
if(!$this->canCreateZip())return false;
if(count($invoice->documents) == 1)return false;
$maxSize = MAX_ZIP_DOCUMENTS_SIZE * 1000;
$i = 0;
foreach($invoice->documents as $document){
if($document->size <= $maxSize)$i++;
if($i > 1){
return true;
}
}
return false;
}
public function getInvoiceDocumentsZip($invitationKey){
if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
return $this->returnError();
}
Session::put('invitation_key', $invitationKey); // track current invitation
$invoice = $invitation->invoice;
if(!count($invoice->documents)){
return Response::view('error', array('error'=>'No documents'), 404);
}
$documents = $invoice->documents->sortBy('size');
$size = 0;
$maxSize = MAX_ZIP_DOCUMENTS_SIZE * 1000;
$toZip = array();
foreach($documents as $document){
$size += $document->size;
if($size > $maxSize)break;
if(!empty($toZip[$document->name])){
$hasSameHash = false;
foreach($toZip[$document->name] as $sameName){
if($sameName->hash == $document->hash){
$hasSameHash = true;
break;
}
}
if(!$hasSameHash){
// 2 different files with the same name
$toZip[$document->name][] = $document;
}
else{
// We're not adding this after all
$size -= $document->size;
}
}
else{
$toZip[$document->name] = array($document);
}
}
if(!count($toZip)){
return Response::view('error', array('error'=>'No documents small enough'), 404);
}
$zip = new \Barracuda\ArchiveStream\ZipArchive($invitation->account->name.' Invoice '.$invoice->invoice_number.'.zip');
return Response::stream(function() use ($toZip, $zip) {
foreach($toZip as $documentsSameName){
$i = 0;
foreach($documentsSameName as $document){
$name = $document->name;
if($i){
$nameInfo = pathinfo($document->name);
$name = $nameInfo['filename'].' ('.$i.').'.$nameInfo['extension'];
}
$fileStream = $document->getStream();
if($fileStream){
$zip->init_file_stream_transfer($name, $document->size);
while ($buffer = fread($fileStream, 8192))$zip->stream_file_part($buffer);
fclose($fileStream);
$zip->complete_file_stream();
}
else{
$zip->add_file($name, $document->getRaw());
}
}
}
$zip->finish();
}, 200);
}
public function getDocument($invitationKey, $publicId){
if (!$invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {

View File

@ -49,6 +49,7 @@ Route::group(['middleware' => 'auth:client'], function() {
Route::get('client/dashboard', 'PublicClientController@dashboard');
Route::get('client/document/js/{public_id}/{filename}', 'PublicClientController@getDocumentVFSJS');
Route::get('client/document/{invitation_key}/{public_id}/{filename?}', 'PublicClientController@getDocument');
Route::get('client/documents/{invitation_key}/{filename?}', 'PublicClientController@getInvoiceDocumentsZip');
});
Route::get('api/client.quotes', array('as'=>'api.client.quotes', 'uses'=>'PublicClientController@quoteDatatable'));
@ -434,6 +435,7 @@ if (!defined('CONTACT_EMAIL')) {
define('MAX_FAILED_LOGINS', 10);
define('MAX_DOCUMENT_SIZE', env('MAX_DOCUMENT_SIZE', 10000));// KB
define('MAX_EMAIL_DOCUMENTS_SIZE', env('MAX_EMAIL_DOCUMENTS_SIZE', 10000));// Total KB
define('MAX_ZIP_DOCUMENTS_SIZE', env('MAX_EMAIL_DOCUMENTS_SIZE', 30000));// Total KB (uncompressed)
define('DOCUMENT_PREVIEW_SIZE', env('DOCUMENT_PREVIEW_SIZE', 300));// pixels
define('DEFAULT_FONT_SIZE', 9);
define('DEFAULT_HEADER_FONT', 1);// Roboto

View File

@ -158,6 +158,7 @@ class DocumentRepository extends BaseRepository
$document->path = $filename;
$document->type = $documentType;
$document->size = $size;
$document->hash = $hash;
$document->name = substr($name, -255);
if(!empty($imageSize)){

View File

@ -68,7 +68,8 @@
"cerdic/css-tidy": "~v1.5",
"asgrim/ofxparser": "^1.1",
"league/flysystem-aws-s3-v3": "~1.0",
"league/flysystem-rackspace": "~1.0"
"league/flysystem-rackspace": "~1.0",
"barracudanetworks/archivestream-php": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0",

44
composer.lock generated
View File

@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "aa7451471a31552d5d6dce491ec20272",
"content-hash": "d70446a01a12bb41eece33b979adc975",
"hash": "5b6b0afc0a26fa2b1dc48241fd665c1e",
"content-hash": "33f39a8d05247b96374ed20e95499936",
"packages": [
{
"name": "agmscode/omnipay-agms",
@ -401,6 +401,46 @@
],
"time": "2016-03-22 19:19:22"
},
{
"name": "barracudanetworks/archivestream-php",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/barracudanetworks/ArchiveStream-php.git",
"reference": "9a81c7de7f0cd5ea2150fc3dc00f1c43178362b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barracudanetworks/ArchiveStream-php/zipball/9a81c7de7f0cd5ea2150fc3dc00f1c43178362b6",
"reference": "9a81c7de7f0cd5ea2150fc3dc00f1c43178362b6",
"shasum": ""
},
"require": {
"ext-gmp": "*",
"ext-mbstring": "*",
"php": ">=5.1.2"
},
"type": "library",
"autoload": {
"psr-4": {
"Barracuda\\ArchiveStream\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A library for dynamically streaming dynamic tar or zip files without the need to have the complete file stored on the server.",
"homepage": "https://github.com/barracudanetworks/ArchiveStream-php",
"keywords": [
"archive",
"php",
"stream",
"tar",
"zip"
],
"time": "2016-01-07 06:02:26"
},
{
"name": "barryvdh/laravel-debugbar",
"version": "v2.2.0",

View File

@ -34,6 +34,7 @@ class AddDocuments extends Migration {
$t->string('name');
$t->string('type');
$t->string('disk');
$t->string('hash', 40);
$t->unsignedInteger('size');
$t->unsignedInteger('width')->nullable();
$t->unsignedInteger('height')->nullable();

View File

@ -1098,6 +1098,7 @@ $LANG = array(
'december' => 'December',
// Documents
'documents_header' => 'Documents:',
'email_documents_header' => 'Documents:',
'email_documents_example_1' => 'Widgets Receipt.pdf',
'email_documents_example_2' => 'Final Deliverable.zip',
@ -1106,6 +1107,7 @@ $LANG = array(
'invoice_embed_documents' => 'Embed Documents',
'invoice_embed_documents_help' => 'Include attached images in the invoice.',
'document_email_attachment' => 'Attach Documents',
'download_documents' => 'Download Documents',
);
return $LANG;

View File

@ -24,7 +24,6 @@
@if ($checkoutComToken)
@include('partials.checkout_com_payment')
@else
<p>&nbsp;</p>
<div class="pull-right" style="text-align:right">
@if ($invoice->is_quote)
{!! Button::normal(trans('texts.download_pdf'))->withAttributes(['onclick' => 'onDownloadClick()'])->large() !!}&nbsp;&nbsp;
@ -39,12 +38,28 @@
<a href='{!! $paymentURL !!}' class="btn btn-success btn-lg">{{ trans('texts.pay_now') }}</a>
@endif
@else
{!! Button::normal('Download PDF')->withAttributes(['onclick' => 'onDownloadClick()'])->large() !!}
{!! Button::normal(trans('texts.download_pdf'))->withAttributes(['onclick' => 'onDownloadClick()'])->large() !!}
@endif
</div>
<div class="pull-left">
@if(!empty($documentsZipURL))
{!! Button::normal(trans('texts.download_documents'))->asLinkTo($documentsZipURL)->large() !!}
@endif
</div>
@endif
<div class="clearfix"></div><p>&nbsp;</p>
@if ($account->isPro() && count($invoice->documents))
<div class="invoice-documents">
<h3>{{ trans('texts.documents_header') }}</h3>
<ul>
@foreach ($invoice->documents as $document)
<li><a target="_blank" href="{{ $document->getClientUrl($invitation) }}">{{$document->name}}</a></li>
@endforeach
</ul>
</div>
@endif
@if ($account->isPro() && $account->invoice_embed_documents)
@foreach ($invoice->documents as $document)
<script src="{{ $document->getClientVFSJSUrl() }}" type="text/javascript" {{ Input::has('phantomjs')?'':'async' }}></script>