mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-31 22:14:36 -04:00
Model encode primary keys (#2510)
* Client Address * Vue components for address * Fix for null objects being passed to Vue * Copy Billing Address * route key * Social auth * Pad out route bindings * Deploy hashes across models * social auth buttons
This commit is contained in:
parent
6769ade16f
commit
af9ae06289
@ -41,20 +41,40 @@ class LoginController extends Controller
|
|||||||
$this->middleware('guest:user')->except('logout');
|
$this->middleware('guest:user')->except('logout');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Once the user is authenticated, we need to set
|
||||||
|
* the default company into a session variable
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function authenticated(Request $request, $user)
|
public function authenticated(Request $request, $user)
|
||||||
{
|
{
|
||||||
$this->setCurrentCompanyId($user->companies()->first()->account->default_company_id);
|
$this->setCurrentCompanyId($user->companies()->first()->account->default_company_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect the user to the provider authentication page
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function redirectToProvider($provider)
|
public function redirectToProvider($provider)
|
||||||
{
|
{
|
||||||
return Socialite::driver($provider)->redirect();
|
return Socialite::driver($provider)->redirect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Received the returning object from the provider
|
||||||
|
* which we will use to resolve the user
|
||||||
|
*
|
||||||
|
* @return redirect
|
||||||
|
*/
|
||||||
public function handleProviderCallback($provider)
|
public function handleProviderCallback($provider)
|
||||||
{
|
{
|
||||||
$user = Socialite::driver('github')->user();
|
$user = Socialite::driver($provider)->user();
|
||||||
|
|
||||||
|
/** If user exists, redirect to dashboard */
|
||||||
|
|
||||||
|
/** If user does not exist, create account sequence */
|
||||||
dd($user);
|
dd($user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Laracasts\Presenter\PresentableTrait;
|
use Laracasts\Presenter\PresentableTrait;
|
||||||
@ -10,6 +11,7 @@ class Account extends BaseModel
|
|||||||
{
|
{
|
||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
use PresentableTrait;
|
use PresentableTrait;
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
|
@ -15,7 +15,7 @@ class Client extends BaseModel
|
|||||||
|
|
||||||
protected $presenter = 'App\Models\Presenters\ClientPresenter';
|
protected $presenter = 'App\Models\Presenters\ClientPresenter';
|
||||||
|
|
||||||
protected $appends = ['client_id'];
|
//protected $appends = ['client_id'];
|
||||||
|
|
||||||
protected $guarded = [
|
protected $guarded = [
|
||||||
'id'
|
'id'
|
||||||
|
@ -2,15 +2,19 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
use Hashids\Hashids;
|
use Hashids\Hashids;
|
||||||
use Illuminate\Notifications\Notifiable;
|
|
||||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
|
||||||
|
|
||||||
class ClientContact extends Authenticatable
|
class ClientContact extends Authenticatable
|
||||||
{
|
{
|
||||||
use Notifiable;
|
use Notifiable;
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
|
protected $appends = ['contact_id'];
|
||||||
|
|
||||||
protected $guard = 'contact';
|
protected $guard = 'contact';
|
||||||
|
|
||||||
@ -19,14 +23,8 @@ class ClientContact extends Authenticatable
|
|||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $fillable = [
|
protected $guarded = [
|
||||||
'first_name',
|
'id',
|
||||||
'last_name',
|
|
||||||
'email',
|
|
||||||
'password',
|
|
||||||
'phone',
|
|
||||||
'custom_value1',
|
|
||||||
'custom_value2',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,6 +36,16 @@ class ClientContact extends Authenticatable
|
|||||||
'password', 'remember_token',
|
'password', 'remember_token',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
public function getRouteKeyName()
|
||||||
|
{
|
||||||
|
return 'contact_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContactIdAttribute()
|
||||||
|
{
|
||||||
|
return $this->encodePrimaryKey($this->id);
|
||||||
|
}
|
||||||
|
|
||||||
public function client()
|
public function client()
|
||||||
{
|
{
|
||||||
|
@ -2,9 +2,29 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
class ClientLocation extends BaseModel
|
class ClientLocation extends BaseModel
|
||||||
{
|
{
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
|
|
||||||
|
protected $appends = ['client_location_id'];
|
||||||
|
|
||||||
|
public function getRouteKeyName()
|
||||||
|
{
|
||||||
|
return 'client_location_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClientLocationIdAttribute()
|
||||||
|
{
|
||||||
|
return $this->encodePrimaryKey($this->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function client()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Client::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,50 +2,40 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use App\Models\Traits\AccountTrait;
|
use App\Models\Traits\AccountTrait;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Laracasts\Presenter\PresentableTrait;
|
use Laracasts\Presenter\PresentableTrait;
|
||||||
|
|
||||||
class Company extends BaseModel
|
class Company extends BaseModel
|
||||||
{
|
{
|
||||||
use PresentableTrait;
|
use PresentableTrait;
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
protected $presenter = 'App\Models\Presenters\CompanyPresenter';
|
protected $presenter = 'App\Models\Presenters\CompanyPresenter';
|
||||||
|
|
||||||
|
protected $guarded = [
|
||||||
protected $fillable = [
|
'id',
|
||||||
|
'company_id'
|
||||||
'name',
|
|
||||||
'address1',
|
|
||||||
'address2',
|
|
||||||
'city',
|
|
||||||
'state',
|
|
||||||
'postal_code',
|
|
||||||
'country_id',
|
|
||||||
'industry_id',
|
|
||||||
'work_phone',
|
|
||||||
'work_email',
|
|
||||||
'language_id',
|
|
||||||
'vat_number',
|
|
||||||
'id_number',
|
|
||||||
'tax_name1',
|
|
||||||
'tax_rate1',
|
|
||||||
'tax_name2',
|
|
||||||
'tax_rate2',
|
|
||||||
'website',
|
|
||||||
'timezone_id',
|
|
||||||
'currency_id',
|
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
//protected $appends = ['company_id'];
|
||||||
|
|
||||||
|
public function getRouteKeyName()
|
||||||
|
{
|
||||||
|
return 'company_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCompanyIdAttribute()
|
||||||
|
{
|
||||||
|
return $this->encodePrimaryKey($this->id);
|
||||||
|
}
|
||||||
|
|
||||||
public function account()
|
public function account()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Account::class);
|
return $this->belongsTo(Account::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function users()
|
public function users()
|
||||||
{
|
{
|
||||||
return $this->hasMany(User::class);
|
return $this->hasMany(User::class);
|
||||||
|
@ -2,9 +2,26 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
class Expense extends BaseModel
|
class Expense extends BaseModel
|
||||||
{
|
{
|
||||||
//
|
use MakesHash;
|
||||||
|
|
||||||
|
protected $guarded = [
|
||||||
|
'id',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $appends = ['expense_id'];
|
||||||
|
|
||||||
|
public function getRouteKeyName()
|
||||||
|
{
|
||||||
|
return 'expense_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExpenseIdAttribute()
|
||||||
|
{
|
||||||
|
return $this->encodePrimaryKey($this->id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,28 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
class Invoice extends BaseModel
|
class Invoice extends BaseModel
|
||||||
{
|
{
|
||||||
//
|
use MakesHash;
|
||||||
|
|
||||||
|
protected $guarded = [
|
||||||
|
'id',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $appends = ['invoice_id'];
|
||||||
|
|
||||||
|
public function getRouteKeyName()
|
||||||
|
{
|
||||||
|
return 'invoice_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInvoiceIdAttribute()
|
||||||
|
{
|
||||||
|
return $this->encodePrimaryKey($this->id);
|
||||||
|
}
|
||||||
|
|
||||||
public function invitations()
|
public function invitations()
|
||||||
{
|
{
|
||||||
|
@ -2,9 +2,26 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
class Payment extends BaseModel
|
class Payment extends BaseModel
|
||||||
{
|
{
|
||||||
//
|
use MakesHash;
|
||||||
|
|
||||||
|
protected $guarded = [
|
||||||
|
'id',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $appends = ['payment_id'];
|
||||||
|
|
||||||
|
public function getRouteKeyName()
|
||||||
|
{
|
||||||
|
return 'payment_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPaymentIdAttribute()
|
||||||
|
{
|
||||||
|
return $this->encodePrimaryKey($this->id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,26 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
class Product extends BaseModel
|
class Product extends BaseModel
|
||||||
{
|
{
|
||||||
//
|
use MakesHash;
|
||||||
|
|
||||||
|
protected $guarded = [
|
||||||
|
'id',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $appends = ['product_id'];
|
||||||
|
|
||||||
|
public function getRouteKeyName()
|
||||||
|
{
|
||||||
|
return 'product_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProductIdAttribute()
|
||||||
|
{
|
||||||
|
return $this->encodePrimaryKey($this->id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,15 +2,28 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
class Proposal extends BaseModel
|
class Proposal extends BaseModel
|
||||||
{
|
{
|
||||||
//
|
use MakesHash;
|
||||||
|
|
||||||
public function invitations()
|
protected $guarded = [
|
||||||
|
'id',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $appends = ['proposal_id'];
|
||||||
|
|
||||||
|
public function getRouteKeyName()
|
||||||
{
|
{
|
||||||
$this->morphMany(Invitation::class, 'inviteable');
|
return 'proposal_id';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getProposalIdAttribute()
|
||||||
|
{
|
||||||
|
return $this->encodePrimaryKey($this->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,27 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
class Task extends BaseModel
|
class Task extends BaseModel
|
||||||
{
|
{
|
||||||
//
|
use MakesHash;
|
||||||
|
|
||||||
|
protected $guarded = [
|
||||||
|
'id',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $appends = ['task_id'];
|
||||||
|
|
||||||
|
public function getRouteKeyName()
|
||||||
|
{
|
||||||
|
return 'task_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTaskIdAttribute()
|
||||||
|
{
|
||||||
|
return $this->encodePrimaryKey($this->id);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,27 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
class TaxRate extends BaseModel
|
class TaxRate extends BaseModel
|
||||||
{
|
{
|
||||||
//
|
use MakesHash;
|
||||||
|
|
||||||
|
protected $guarded = [
|
||||||
|
'id',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $appends = ['tax_rate_id'];
|
||||||
|
|
||||||
|
public function getRouteKeyName()
|
||||||
|
{
|
||||||
|
return 'tax_rate_id';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTaxRateIdAttribute()
|
||||||
|
{
|
||||||
|
return $this->encodePrimaryKey($this->id);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,11 @@ namespace App\Models;
|
|||||||
|
|
||||||
use App\Models\Traits\SetsUserSessionAttributes;
|
use App\Models\Traits\SetsUserSessionAttributes;
|
||||||
use App\Models\Traits\UserTrait;
|
use App\Models\Traits\UserTrait;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Notifications\Notifiable;
|
|
||||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
|
use Illuminate\Notifications\Notifiable;
|
||||||
use Laracasts\Presenter\PresentableTrait;
|
use Laracasts\Presenter\PresentableTrait;
|
||||||
|
|
||||||
class User extends Authenticatable implements MustVerifyEmail
|
class User extends Authenticatable implements MustVerifyEmail
|
||||||
@ -15,7 +16,8 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||||||
use Notifiable;
|
use Notifiable;
|
||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
use PresentableTrait;
|
use PresentableTrait;
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
protected $guard = 'user';
|
protected $guard = 'user';
|
||||||
|
|
||||||
protected $dates = ['deleted_at'];
|
protected $dates = ['deleted_at'];
|
||||||
|
@ -31,6 +31,57 @@ class RouteServiceProvider extends ServiceProvider
|
|||||||
Route::bind('client', function ($value) {
|
Route::bind('client', function ($value) {
|
||||||
return \App\Models\Client::where('id', $this->decodePrimaryKey($value))->first() ?? abort(404);
|
return \App\Models\Client::where('id', $this->decodePrimaryKey($value))->first() ?? abort(404);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::bind('invoice', function ($value) {
|
||||||
|
return \App\Models\Invoice::where('id', $this->decodePrimaryKey($value))->first() ?? abort(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::bind('payment', function ($value) {
|
||||||
|
return \App\Models\Payment::where('id', $this->decodePrimaryKey($value))->first() ?? abort(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::bind('product', function ($value) {
|
||||||
|
return \App\Models\Product::where('id', $this->decodePrimaryKey($value))->first() ?? abort(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::bind('company', function ($value) {
|
||||||
|
return \App\Models\Company::where('id', $this->decodePrimaryKey($value))->first() ?? abort(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::bind('account', function ($value) {
|
||||||
|
return \App\Models\Account::where('id', $this->decodePrimaryKey($value))->first() ?? abort(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::bind('client_contact', function ($value) {
|
||||||
|
return \App\Models\ClientContact::where('id', $this->decodePrimaryKey($value))->first() ?? abort(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::bind('client_location', function ($value) {
|
||||||
|
return \App\Models\ClientLocation::where('id', $this->decodePrimaryKey($value))->first() ?? abort(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::bind('expense', function ($value) {
|
||||||
|
return \App\Models\Expense::where('id', $this->decodePrimaryKey($value))->first() ?? abort(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::bind('invitation', function ($value) {
|
||||||
|
return \App\Models\Invitation::where('id', $this->decodePrimaryKey($value))->first() ?? abort(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::bind('task', function ($value) {
|
||||||
|
return \App\Models\Task::where('id', $this->decodePrimaryKey($value))->first() ?? abort(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::bind('tax_rate', function ($value) {
|
||||||
|
return \App\Models\TaxRate::where('id', $this->decodePrimaryKey($value))->first() ?? abort(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::bind('proposal', function ($value) {
|
||||||
|
return \App\Models\Proposal::where('id', $this->decodePrimaryKey($value))->first() ?? abort(404);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,6 +52,33 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row mt-4">
|
||||||
|
<hr>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mt-4" id="app">
|
||||||
|
<div class="col-3 text-center">
|
||||||
|
<button type="button" class="btn btn-lg btn-brand btn-google" @click="this.window.location.href='/auth/google'" >
|
||||||
|
<i class="fa fa-google"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-3 text-center">
|
||||||
|
<button type="button" class="btn btn-lg btn-brand btn-facebook" @click="this.window.location.href='/auth/facebook'">
|
||||||
|
<i class="fa fa-facebook"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-3 text-center">
|
||||||
|
<button type="button" class="btn btn-lg btn-brand btn-github" @click="this.window.location.href='/auth/github'">
|
||||||
|
<i class="fa fa-github"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col-3 text-center">
|
||||||
|
<button type="button" class="btn btn-lg btn-brand btn-linkedin" @click="this.window.location.href='/auth/linkedin'">
|
||||||
|
<i class="fa fa-linkedin"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
<footer class="app-footer">
|
<footer class="app-footer">
|
||||||
<div>
|
|
||||||
<a href="https://invoiceninja.com">Invoice Ninja</a>
|
|
||||||
<span>© 2018 Invoice Ninja LLC.</span>
|
|
||||||
</div>
|
|
||||||
<div class="ml-auto">
|
<div class="ml-auto">
|
||||||
<span>Powered by</span>
|
<span>Powered by</span>
|
||||||
<a href="https://invoiceninja.com">InvoiceNinja</a>
|
<a href="https://invoiceninja.com">InvoiceNinja</a> © 2018 Invoice Ninja LLC.
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user