1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-05 18:52:44 +01:00

Presenters, skinned views, model refactoring (#2464)

* Default database connection - set defaults for engine and strict

* Working on tests for refactored model

* Fixes for tests, use polymorphic relationships for Invitations

* skin the password reset pages
This commit is contained in:
David Bomba 2018-10-22 23:04:37 +11:00 committed by GitHub
parent 50e22ee1d6
commit e4f46c2a4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 940 additions and 577 deletions

View File

@ -8,44 +8,10 @@
*
*/
if (! defined('APP_NAME')) {
define('APP_NAME', env('APP_NAME', 'Invoice Ninja'));
define('APP_DOMAIN', env('APP_DOMAIN', 'invoiceninja.com'));
define('CONTACT_EMAIL', env('MAIL_FROM_ADDRESS'));
define('CONTACT_NAME', env('MAIL_FROM_NAME'));
define('SITE_URL', env('APP_URL'));
define('APP_VERSION', env('APP_VERSION'));
define('NINJA_TERMS_VERSION', '1.0.1');
define('ENV_DEVELOPMENT', 'local');
define('ENV_STAGING', 'staging');
define('BANK_LIBRARY_OFX', 1);
define('RANDOM_KEY_LENGTH', 32); //63340286662973277706162286946811886609896461828096 combinations
define('TEST_USERNAME', env('TEST_USERNAME', 'user@example.com'));
define('TEST_CLIENTNAME', env('TEST_CLIENTNAME', 'client@example.com'));
define('TEST_PASSWORD', 'password');
define('BANK_LIBRARY_OFX', 1);
//define('MULTI_DBS', serialize(['db-ninja-1', 'db-ninja-2']));
define('RANDOM_KEY_LENGTH', 32); //63340286662973277706162286946811886609896461828096 combinations
define('SOCIAL_GOOGLE', 'Google');
define('SOCIAL_FACEBOOK', 'Facebook');
define('SOCIAL_GITHUB', 'GitHub');
define('SOCIAL_LINKEDIN', 'LinkedIn');
define('SOCIAL_TWITTER', 'Twitter');
define('SOCIAL_BITBUCKET', 'Bitbucket');
define('CURRENCY_DOLLAR', 1);
define('CURRENCY_EURO', 3);
define('DEFAULT_TIMEZONE', 'US/Eastern');
define('DEFAULT_COUNTRY', 840); // United Stated
define('DEFAULT_CURRENCY', CURRENCY_DOLLAR);
define('DEFAULT_LANGUAGE', 1); // English
define('DEFAULT_DATE_FORMAT', 'M j, Y');
define('DEFAULT_DATE_PICKER_FORMAT', 'M d, yyyy');
define('DEFAULT_DATETIME_FORMAT', 'F j, Y g:i a');
define('DEFAULT_DATETIME_MOMENT_FORMAT', 'MMM D, YYYY h:mm:ss a');
define('DEFAULT_LOCALE', 'en');
define('DEFAULT_MAP_ZOOM', 10);
}

View File

@ -0,0 +1,105 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\SignupRequest;
use App\Jobs\RegisterNewAccount;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
class CompanyController extends Controller
{
use DispatchesJobs;
public function __construct()
{
$this->middleware('guest');
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
return view('signup.index');
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \App\Http\Requests\SignupRequest $request
* @return \Illuminate\Http\Response
*/
public function store(SignupRequest $request)
{
$user = RegisterNewAccount::dispatchNow($request);
//log user in
Auth::guard('user')->login($user, true);
//todo redirect to localization setup workflow
return redirect()->route('user.dashboard');
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}

View File

@ -1,84 +0,0 @@
<?php
namespace App\Http\Controllers;
use App\Events\UserSignedUp;
use App\Http\Requests\SignupRequest;
use App\Jobs\Account\AccountCreated;
use App\Models\Account;
use App\Models\User;
use App\Models\UserAccount;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
/**
* Class SignupController
* @package App\Http\Controllers
*/
class SignupController extends Controller
{
use DispatchesJobs;
/**
* SignupController constructor.
*/
public function __construct()
{
$this->middleware('guest');
}
/**
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function signup()
{
return view('signup.index');
}
/**
* @param SignupRequest $request
*/
public function processSignup(SignupRequest $request)
{
//dd($request->validated());
//created new account
$ac = new Account();
$ac->name = $request->first_name. ' ' .$request->last_name;
$ac->account_key = strtolower(str_random(RANDOM_KEY_LENGTH));
$ac->ip = $request->ip();
$ac->save();
$user = new User();
$user->password = Hash::make($request->input('password'));
$user->accepted_terms_version = NINJA_TERMS_VERSION;
$user->confirmation_code = strtolower(str_random(RANDOM_KEY_LENGTH));
$user->db = config('database.default');
$user->fill($request->all());
$user->save();
$user_account = new UserAccount();
$user_account->user_id = $user->id;
$user_account->account_id = $ac->id;
$user_account->is_owner = TRUE;
$user_account->is_admin = TRUE;
$user_account->is_default = TRUE;
$user_account->is_locked = FALSE;
$user_account->permissions = '';
$user_account->save();
//log user in
Auth::guard('user')->login($user, true);
//fire account created job
event(new UserSignedUp($user));
//redirect to localization setup workflow
return redirect()->route('user.dashboard');
}
}

View File

@ -0,0 +1,81 @@
<?php
namespace App\Jobs;
use App\Events\UserSignedUp;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Http\Request;
use App\Models\Account;
use App\Models\Company;
use App\Models\User;
use App\Models\UserCompany;
use Illuminate\Support\Facades\Hash;
class RegisterNewAccount
{
use Dispatchable;
protected $request;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$ac = new Account();
$ac->utm_source = $this->request->input('utm_source');
$ac->utm_medium = $this->request->input('utm_medium');
$ac->utm_campaign = $this->request->input('utm_campaign');
$ac->utm_term = $this->request->input('utm_term');
$ac->utm_content = $this->request->input('utm_content');
$ac->save();
$company = new Company();
$company->account_id = $ac->id;
$company->name = $this->request->first_name . ' ' . $this->request->last_name;
$company->company_key = strtolower(str_random(RANDOM_KEY_LENGTH));
$company->ip = $this->request->ip();
$company->save();
$user = new User();
$user->account_id = $ac->id;
$user->password = Hash::make($this->request->input('password'));
$user->accepted_terms_version = config('ninja.terms_version');
$user->confirmation_code = strtolower(str_random(RANDOM_KEY_LENGTH));
$user->db = config('database.default');
$user->fill($this->request->all());
$user->save();
$user_account = new UserCompany();
$user_account->user_id = $user->id;
$user_account->account_id = $ac->id;
$user_account->company_id = $company->id;
$user_account->is_owner = TRUE;
$user_account->is_admin = TRUE;
$user_account->permissions = '';
$user_account->save();
$ac->default_company_id = $ac->id;
$ac->save();
//fire account created job
event(new UserSignedUp($user));
return $user;
}
}

View File

@ -32,4 +32,42 @@ class OAuth
}
}
public static function providerToString($social_provider)
{
switch ($social_provider)
{
case SOCIAL_GOOGLE:
return 'google';
case SOCIAL_FACEBOOK:
return 'facebook';
case SOCIAL_GITHUB:
return 'github';
case SOCIAL_LINKEDIN:
return 'linkedin';
case SOCIAL_TWITTER:
return 'twitter';
case SOCIAL_BITBUCKET:
return 'bitbucket';
}
}
public static function providerToInt($social_provider)
{
switch ($social_provider)
{
case 'google':
return SOCIAL_GOOGLE;
case 'facebook':
return SOCIAL_FACEBOOK;
case 'github':
return SOCIAL_GITHUB;
case 'linkedin':
return SOCIAL_LINKEDIN;
case 'twitter':
return SOCIAL_TWITTER;
case 'bitbucket':
return SOCIAL_BITBUCKET;
}
}
}

View File

@ -3,155 +3,53 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Models\Traits\AccountTrait;
use Illuminate\Database\Eloquent\SoftDeletes;
use Laracasts\Presenter\PresentableTrait;
class Account extends Model
{
use AccountTrait;
use SoftDeletes;
use PresentableTrait;
/**
* @var string
*/
protected $presenter = 'App\Models\Presenters\AccountPresenter';
/**
* @var array
*/
protected $fillable = [
'timezone_id',
'currency_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',
'plan',
'plan_term',
'plan_price',
'plan_paid',
'plan_started',
'plan_expires',
];
public function users()
{
return $this->hasMany(User::class);
}
/**
* @var array
*/
protected $dates = [
'deleted_at',
'promo_expires',
'discount_expires',
];
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function clients()
public function companies()
{
return $this->hasMany(Client::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function contacts()
{
return $this->hasMany(Contact::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function invoices()
{
return $this->hasMany(Invoice::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function account_gateways()
{
return $this->hasMany(AccountGateway::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function tax_rates()
{
return $this->hasMany(TaxRate::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function products()
{
return $this->hasMany(Product::class);
return $this->hasMany(Company::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function country()
public function payment()
{
return $this->belongsTo(Country::class);
return $this->belongsTo(Payment::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function timezone()
{
return $this->belongsTo(Timezone::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function language()
{
return $this->belongsTo(Language::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function currency()
{
return $this->belongsTo(Currency::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function industry()
{
return $this->belongsTo(Industry::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function payment_type()
{
return $this->belongsTo(PaymentType::class);
}
/**
* @return mixed
*/
public function expenses()
{
return $this->hasMany(Expense::class, 'account_id', 'id')->withTrashed();
}
/**
* @return mixed
*/
public function payments()
{
return $this->hasMany(Payment::class, 'account_id', 'id')->withTrashed();
}
}

161
app/Models/Company.php Normal file
View File

@ -0,0 +1,161 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Models\Traits\AccountTrait;
class Company extends Model
{
protected $fillable = [
'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',
];
public function account()
{
return $this->hasOne(Account::class);
}
public function users()
{
return $this->hasMany(User::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function clients()
{
return $this->hasMany(Client::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function contacts()
{
return $this->hasMany(Contact::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function invoices()
{
return $this->hasMany(Invoice::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function account_gateways()
{
return $this->hasMany(AccountGateway::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function tax_rates()
{
return $this->hasMany(TaxRate::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function products()
{
return $this->hasMany(Product::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function country()
{
return $this->belongsTo(Country::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function timezone()
{
return $this->belongsTo(Timezone::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function language()
{
return $this->belongsTo(Language::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function currency()
{
return $this->belongsTo(Currency::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function industry()
{
return $this->belongsTo(Industry::class);
}
/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function payment_type()
{
return $this->belongsTo(PaymentType::class);
}
/**
* @return mixed
*/
public function expenses()
{
return $this->hasMany(Expense::class, 'account_id', 'id')->withTrashed();
}
/**
* @return mixed
*/
public function payments()
{
return $this->hasMany(Payment::class, 'account_id', 'id')->withTrashed();
}
}

View File

@ -6,5 +6,17 @@ use Illuminate\Database\Eloquent\Model;
class Invitation extends Model
{
//
public function invoices()
{
return $this->morphedByMany(Invoice::class, 'inviteable');
}
public function proposals()
{
return $this->morphedByMany(Proposal::class, 'taggable');
}
}

View File

@ -7,4 +7,9 @@ use Illuminate\Database\Eloquent\Model;
class Invoice extends Model
{
//
public function invitations()
{
$this->morphMany(Invitation::class, 'inviteable');
}
}

View File

@ -4,7 +4,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Payments extends Model
class Payment extends Model
{
//
}

View File

@ -0,0 +1,14 @@
<?php
namespace App\Models\Presenters;
use Laracasts\Presenter\Presenter;
/**
* Class AccountPresenter.
*/
class AccountPresenter extends Presenter
{
}

View File

@ -0,0 +1,53 @@
<?php
namespace App\Models\Presenters;
use Laracasts\Presenter\Presenter;
use URL;
use Utils;
use stdClass;
class EntityPresenter extends Presenter
{
public function url()
{
}
public function path()
{
}
public function editUrl()
{
}
public function statusLabel($label = false)
{
}
public function statusColor()
{
}
public function link()
{
}
public function titledName()
{
}
public function calendarEvent($subColors = false)
{
}
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\models\Presenters;
class UserPresenter extends EntityPresenter
{
public function name()
{
return $this->entity->first_name . ' ' . $this->entity->last_name;
}
}

16
app/Models/Proposal.php Normal file
View File

@ -0,0 +1,16 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Proposal extends Model
{
//
public function invitations()
{
$this->morphMany(Invitation::class, 'inviteable');
}
}

View File

@ -1,18 +0,0 @@
<?php
namespace App\Models\Traits;
trait AccountTrait
{
public function getDisplayName()
{
if ($this->name) {
return $this->name;
}
$user = $this->users()->first();
return $user->getDisplayName();
}
}

View File

@ -1,34 +0,0 @@
<?php
namespace App\Models\Traits;
trait UserTrait
{
/**
* @return mixed|string
*/
public function getDisplayName()
{
if ($this->getFullName()) {
return $this->getFullName();
} elseif ($this->email) {
return $this->email;
} else {
return trans('texts.guest');
}
}
/**
* @return string
*/
public function getFullName()
{
if ($this->first_name || $this->last_name) {
return $this->first_name.' '.$this->last_name;
} else {
return '';
}
}
}

View File

@ -7,17 +7,21 @@ use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Laracasts\Presenter\PresentableTrait;
class User extends Authenticatable
{
use Notifiable;
use SoftDeletes;
use UserTrait;
use PresentableTrait;
protected $guard = 'user';
protected $dates = ['deleted_at'];
protected $presenter = 'App\Models\Presenters\UserPresenter';
/**
* The attributes that are mass assignable.
*

View File

@ -4,7 +4,7 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class UserAccount extends Model
class UserCompany extends Model
{
//
}

View File

@ -2,6 +2,8 @@
namespace App\Providers;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
@ -13,7 +15,14 @@ class AppServiceProvider extends ServiceProvider
*/
public function boot()
{
//
Relation::morphMap([
'invoices' => '\App\Models\Invoice',
'proposals' => '\App\Models\Proposal',
]);
Blade::if('env', function($environment){
return config('ninja.environment') === $environment;
});
}
/**

View File

@ -22,6 +22,7 @@
"asgrim/ofxparser": "^1.2",
"davejamesmiller/laravel-breadcrumbs": "5.x",
"fideloper/proxy": "^4.0",
"laracasts/presenter": "^0.2.1",
"laravel/framework": "5.7.*",
"laravel/socialite": "^3.1",
"laravel/tinker": "^1.0",

82
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "c51e927ba0169fada853f1d0763470ed",
"content-hash": "9701bf39988e968400a53c290122596f",
"packages": [
{
"name": "asgrim/ofxparser",
@ -748,6 +748,52 @@
],
"time": "2015-04-20T18:58:01+00:00"
},
{
"name": "laracasts/presenter",
"version": "0.2.1",
"source": {
"type": "git",
"url": "https://github.com/laracasts/Presenter.git",
"reference": "b284f3137f990efd6e95df49d254f1ccc4541e92"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laracasts/Presenter/zipball/b284f3137f990efd6e95df49d254f1ccc4541e92",
"reference": "b284f3137f990efd6e95df49d254f1ccc4541e92",
"shasum": ""
},
"require": {
"illuminate/support": "~5.0",
"php": ">=5.4.0"
},
"require-dev": {
"mockery/mockery": "~0.9",
"phpspec/phpspec": "~2.0"
},
"type": "library",
"autoload": {
"psr-0": {
"Laracasts\\Presenter": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jeffrey Way",
"email": "jeffrey@laracasts.com"
}
],
"description": "Simple view presenters",
"keywords": [
"laravel",
"presenter",
"view"
],
"time": "2014-09-13T13:18:07+00:00"
},
{
"name": "laravel/framework",
"version": "v5.7.9",
@ -3224,16 +3270,16 @@
},
{
"name": "filp/whoops",
"version": "2.2.1",
"version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/filp/whoops.git",
"reference": "e79cd403fb77fc8963a99ecc30e80ddd885b3311"
"reference": "a9f129b99df316f847584d482c89c14a9f796e2b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/filp/whoops/zipball/e79cd403fb77fc8963a99ecc30e80ddd885b3311",
"reference": "e79cd403fb77fc8963a99ecc30e80ddd885b3311",
"url": "https://api.github.com/repos/filp/whoops/zipball/a9f129b99df316f847584d482c89c14a9f796e2b",
"reference": "a9f129b99df316f847584d482c89c14a9f796e2b",
"shasum": ""
},
"require": {
@ -3281,7 +3327,7 @@
"throwable",
"whoops"
],
"time": "2018-06-30T13:14:06+00:00"
"time": "2018-10-20T09:00:00+00:00"
},
{
"name": "fzaninotto/faker",
@ -3876,16 +3922,16 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "6.1.0",
"version": "6.1.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "0685fb6a43aed1b2e09804d1aaf17144c82861f8"
"reference": "b097681a19a48e52706f57e47a09594bac4f7cab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/0685fb6a43aed1b2e09804d1aaf17144c82861f8",
"reference": "0685fb6a43aed1b2e09804d1aaf17144c82861f8",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b097681a19a48e52706f57e47a09594bac4f7cab",
"reference": "b097681a19a48e52706f57e47a09594bac4f7cab",
"shasum": ""
},
"require": {
@ -3896,7 +3942,7 @@
"phpunit/php-text-template": "^1.2.1",
"phpunit/php-token-stream": "^3.0",
"sebastian/code-unit-reverse-lookup": "^1.0.1",
"sebastian/environment": "^3.1",
"sebastian/environment": "^3.1 || ^4.0",
"sebastian/version": "^2.0.1",
"theseer/tokenizer": "^1.1"
},
@ -3935,7 +3981,7 @@
"testing",
"xunit"
],
"time": "2018-10-16T05:37:37+00:00"
"time": "2018-10-18T09:01:38+00:00"
},
{
"name": "phpunit/php-file-iterator",
@ -4128,16 +4174,16 @@
},
{
"name": "phpunit/phpunit",
"version": "7.4.0",
"version": "7.4.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "f3837fa1e07758057ae06e8ddec6d06ba183f126"
"reference": "c5a120ade60992bd671a912188ee9ee9f8083bbd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3837fa1e07758057ae06e8ddec6d06ba183f126",
"reference": "f3837fa1e07758057ae06e8ddec6d06ba183f126",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c5a120ade60992bd671a912188ee9ee9f8083bbd",
"reference": "c5a120ade60992bd671a912188ee9ee9f8083bbd",
"shasum": ""
},
"require": {
@ -4158,7 +4204,7 @@
"phpunit/php-timer": "^2.0",
"sebastian/comparator": "^3.0",
"sebastian/diff": "^3.0",
"sebastian/environment": "^3.1",
"sebastian/environment": "^3.1 || ^4.0",
"sebastian/exporter": "^3.1",
"sebastian/global-state": "^2.0",
"sebastian/object-enumerator": "^3.0.3",
@ -4208,7 +4254,7 @@
"testing",
"xunit"
],
"time": "2018-10-05T04:05:24+00:00"
"time": "2018-10-18T09:02:52+00:00"
},
{
"name": "sebastian/code-unit-reverse-lookup",

View File

@ -51,8 +51,8 @@ return [
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => false,
'engine' => null,
'strict' => env('DB_STRICT', false),
'engine' => 'InnoDB',
],
'pgsql' => [

View File

@ -3,8 +3,13 @@
return [
'web_url' => 'https://www.invoiceninja.com',
'app_url' => 'https://app-v5.invoiceninja.com',
'site_url' => '',
'app_name' => env('APP_NAME'),
'site_url' => env('APP_URL', 'https://app-v5.invoiceninja.com'),
'app_domain' => env('APP_DOMAIN', 'invoiceninja.com'),
'app_version' => '0.1',
'terms_version' => '1.0.1',
'app_env' => env('APP_ENV', 'development'),
'environment' => env('NINJA_ENVIRONMENT', 'selfhost'), // 'hosted', 'development', 'selfhost', 'reseller'
// Settings used by invoiceninja.com
@ -22,5 +27,30 @@ return [
'db' => [
'multi_db_enabled' => env('MULTI_DB_ENABLED', false),
'default' => env('DB_CONNECTION', 'mysql'),
]
],
'i18n' => [
'timezone' => env('DEFAULT_TIMEZONE', 'US/Eastern'),
'country' => env('DEFAULT_COUNTRY', 840), // United Stated
'currency' => env('DEFAULT_CURRENCY', 1), //USD
'language' => env('DEFAULT_LANGUAGE', 1), //en
'date_format' => env('DEFAULT_DATE_FORMAT', 'M j, Y'),
'date_picker_format' => env('DEFAULT_DATE_PICKER_FORMAT', 'M d, yyyy'),
'datetime_format' => env('DEFAULT_DATETIME_FORMAT', 'F j, Y g:i a'),
'datetime_momemnt_format' => env('DEFAULT_DATETIME_MOMENT_FORMAT', 'MMM D, YYYY h:mm:ss a'),
'locale' => env('DEFAULT_LOCALE', 'en'),
'map_zoom' => env('DEFAULT_MAP_ZOOM', 10),
],
'testvars' => [
'username' => 'user@example.com',
'clientname' => 'client@example.com',
'password' => 'password',
],
'contact' => [
'email' => env('MAIL_FROM_ADDRESS'),
'from_name' => env('MAIL_FROM_NAME'),
],
];

View File

@ -0,0 +1,9 @@
<?php
use Faker\Generator as Faker;
$factory->define(App\Models\Account::class, function (Faker $faker) {
return [
//
];
});

View File

@ -0,0 +1,11 @@
<?php
use Faker\Generator as Faker;
$factory->define(App\Models\Company::class, function (Faker $faker) {
return [
'name' => $faker->name,
'company_key' => strtolower(str_random(RANDOM_KEY_LENGTH)),
'ip' => $faker->ipv4
];
});

View File

@ -78,14 +78,54 @@ class CreateUsersTable extends Migration
$table->boolean('visible')->default(true);
});
Schema::create('accounts', function ($table) {
$table->increments('id');
$table->enum('plan', ['pro', 'enterprise', 'white_label'])->nullable();
$table->enum('plan_term', ['month', 'year'])->nullable();
$table->date('plan_started')->nullable();
$table->date('plan_paid')->nullable();
$table->date('plan_expires')->nullable();
$table->unsignedInteger('payment_id')->nullable()->index();
$table->unsignedInteger('default_company_id');
$table->date('trial_started')->nullable();
$table->enum('trial_plan', ['pro', 'enterprise'])->nullable();
$table->enum('pending_plan', ['pro', 'enterprise', 'free'])->nullable();
$table->enum('pending_term', ['month', 'year'])->nullable();
$table->decimal('plan_price', 7, 2)->nullable();
$table->decimal('pending_plan_price', 7, 2)->nullable();
$table->smallInteger('num_users')->default(1);
$table->smallInteger('pending_num_users')->default(1);
$table->string('utm_source')->nullable();
$table->string('utm_medium')->nullable();
$table->string('utm_campaign')->nullable();
$table->string('utm_term')->nullable();
$table->string('utm_content')->nullable();
$table->float('discount');
$table->date('discount_expires')->nullable();
$table->enum('bluevine_status', ['ignored', 'signed_up'])->nullable();
$table->string('referral_code')->nullable();
$table->timestamps();
$table->softDeletes();
});
Schema::create('accounts', function (Blueprint $table) {
Schema::create('companies', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->nullable();
$table->unsignedInteger('timezone_id')->nullable();
$table->unsignedInteger('account_id')->index();
$table->unsignedInteger('currency_id')->nullable();
$table->string('ip');
$table->string('account_key',100)->unique();
$table->string('company_key',100)->unique();
$table->timestamp('last_login')->nullable();
$table->string('address1')->nullable();
$table->string('address2')->nullable();
@ -107,36 +147,41 @@ class CreateUsersTable extends Migration
$table->foreign('currency_id')->references('id')->on('currencies');
$table->foreign('industry_id')->references('id')->on('industries');
$table->foreign('size_id')->references('id')->on('sizes');
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
});
Schema::create('user_accounts', function (Blueprint $table) {
Schema::create('user_companies', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('account_id')->index();
$table->unsignedInteger('company_id');
$table->unsignedInteger('account_id');
$table->unsignedInteger('user_id')->index();
$table->text('permissions');
$table->boolean('is_owner');
$table->boolean('is_admin');
$table->boolean('is_locked'); // locks user out of account
$table->boolean('is_default'); //default account to present to the user
$table->boolean('is_locked')->default(false); // locks user out of account
$table->timestamps();
$table->softDeletes();
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
$table->index(['account_id', 'company_id']);
});
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('account_id')->index();
$table->string('first_name')->nullable();
$table->string('last_name')->nullable();
$table->string('phone')->nullable();
$table->string('email',100)->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('confirmation_code')->nullable();
$table->boolean('registered')->default(false);
$table->boolean('confirmed')->default(false);
$table->integer('theme_id')->nullable();
$table->smallInteger('failed_logins')->nullable();
$table->string('referral_code')->nullable();
@ -144,10 +189,11 @@ class CreateUsersTable extends Migration
$table->unsignedInteger('oauth_provider_id')->nullable()->unique();
$table->string('google_2fa_secret')->nullable();
$table->string('accepted_terms_version')->nullable();
$table->string('avatar', 255)->default('');
$table->string('avatar', 100)->default('');
$table->unsignedInteger('avatar_width')->nullable();
$table->unsignedInteger('avatar_height')->nullable();
$table->unsignedInteger('avatar_size')->nullable();
$table->string('db', 100);
$table->text('signature');
$table->string('password');
$table->rememberToken();
@ -155,14 +201,14 @@ class CreateUsersTable extends Migration
$table->timestamps();
$table->softDeletes();
//$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
});
Schema::create('clients', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('account_id')->index();
$table->unsignedInteger('company_id')->index();
$table->unsignedInteger('user_id')->index();
$table->string('name')->nullable();
@ -181,7 +227,7 @@ class CreateUsersTable extends Migration
$table->timestamps();
$table->softDeletes();
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
$table->foreign('industry_id')->references('id')->on('industries');
$table->foreign('size_id')->references('id')->on('sizes');
$table->foreign('currency_id')->references('id')->on('currencies');
@ -210,9 +256,9 @@ class CreateUsersTable extends Migration
});
Schema::create('contacts', function (Blueprint $table) {
Schema::create('client_contacts', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('account_id')->index();
$table->unsignedInteger('company_id')->index();
$table->unsignedInteger('client_id')->index();
$table->unsignedInteger('user_id')->index();
$table->string('first_name')->nullable();
@ -232,21 +278,22 @@ class CreateUsersTable extends Migration
$table->unsignedInteger('avatar_width')->nullable();
$table->unsignedInteger('avatar_height')->nullable();
$table->unsignedInteger('avatar_size')->nullable();
$table->string('db', 100);
$table->string('password');
$table->rememberToken();
$table->timestamps();
$table->softDeletes();
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
$table->foreign('client_id')->references('id')->on('clients')->onDelete('cascade');
$table->unique(['account_id', 'email']);
$table->unique(['company_id', 'email']);
});
Schema::create('account_gateways', function($table)
{
$table->increments('id');
$table->unsignedInteger('account_id')->unique();
$table->unsignedInteger('company_id')->unique();
$table->unsignedInteger('user_id');
$table->unsignedInteger('gateway_id');
$table->boolean('show_address')->default(true)->nullable();
@ -257,7 +304,7 @@ class CreateUsersTable extends Migration
$table->softDeletes();
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
$table->foreign('gateway_id')->references('id')->on('gateways');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
@ -268,7 +315,7 @@ class CreateUsersTable extends Migration
$t->increments('id');
$t->unsignedInteger('client_id')->index();
$t->unsignedInteger('user_id');
$t->unsignedInteger('account_id')->index();
$t->unsignedInteger('company_id')->index();
$t->unsignedInteger('invoice_status_id');
$t->string('invoice_number');
@ -293,20 +340,22 @@ class CreateUsersTable extends Migration
$t->decimal('partial', 13, 2)->nullable();
$t->foreign('client_id')->references('id')->on('clients')->onDelete('cascade');
$t->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
$t->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
$t->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$t->timestamps();
$t->softDeletes();
$t->unique(['account_id', 'client_id']);
$t->unique(['company_id', 'client_id']);
});
Schema::create('invitations', function ($t) {
$t->increments('id');
$t->unsignedInteger('account_id');
$t->unsignedInteger('company_id');
$t->unsignedInteger('inviteable_id');
$t->string('inviteable_type');
$t->unsignedInteger('user_id');
$t->unsignedInteger('contact_id');
$t->unsignedInteger('client_contact_id');
$t->unsignedInteger('invoice_id')->index();
$t->string('invitation_key',100)->index()->unique();
$t->timestamps();
@ -317,23 +366,24 @@ class CreateUsersTable extends Migration
$t->timestamp('viewed_date')->nullable();
$t->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$t->foreign('contact_id')->references('id')->on('contacts')->onDelete('cascade');
$t->foreign('client_contact_id')->references('id')->on('client_contacts')->onDelete('cascade');
$t->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade');
$t->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
});
Schema::create('tax_rates', function ($t) {
$t->increments('id');
$t->unsignedInteger('account_id')->index();
$t->unsignedInteger('user_id');
$t->unsignedInteger('company_id')->index();
$t->unsignedInteger('user_id')->nullable();
$t->timestamps();
$t->softDeletes();
$t->string('name',100)->unique();
$t->decimal('rate', 13, 3);
$t->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
$t->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
$t->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
@ -341,7 +391,7 @@ class CreateUsersTable extends Migration
Schema::create('products', function ($t) {
$t->increments('id');
$t->unsignedInteger('account_id')->index();
$t->unsignedInteger('company_id')->index();
$t->unsignedInteger('user_id');
@ -353,7 +403,7 @@ class CreateUsersTable extends Migration
$t->unsignedInteger('stock_level');
$t->unsignedInteger('min_stock_level');
$t->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
$t->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
$t->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
@ -365,9 +415,9 @@ class CreateUsersTable extends Migration
Schema::create('payments', function ($t) {
$t->increments('id');
$t->unsignedInteger('invoice_id')->nullable()->index(); //todo handle payments where there is no invoice OR we are paying MULTIPLE invoices
$t->unsignedInteger('account_id')->index();
$t->unsignedInteger('company_id')->index();
$t->unsignedInteger('client_id')->index();
$t->unsignedInteger('contact_id')->nullable();
$t->unsignedInteger('client_contact_id')->nullable();
$t->unsignedInteger('invitation_id')->nullable();
$t->unsignedInteger('user_id')->nullable();
$t->unsignedInteger('account_gateway_id')->nullable();
@ -382,9 +432,9 @@ class CreateUsersTable extends Migration
$t->string('payer_id')->nullable();
$t->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade');
$t->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
$t->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
$t->foreign('client_id')->references('id')->on('clients')->onDelete('cascade');
$t->foreign('contact_id')->references('id')->on('contacts')->onDelete('cascade');
$t->foreign('client_contact_id')->references('id')->on('client_contacts')->onDelete('cascade');
$t->foreign('account_gateway_id')->references('id')->on('account_gateways')->onDelete('cascade');
$t->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
;
@ -398,7 +448,7 @@ class CreateUsersTable extends Migration
$table->string('locale');
});
Schema::table('accounts', function ($table) {
Schema::table('companies', function ($table) {
$table->unsignedInteger('language_id')->default(1);
$table->foreign('language_id')->references('id')->on('languages');
});
@ -426,7 +476,7 @@ class CreateUsersTable extends Migration
$table->foreign('payment_library_id')->references('id')->on('payment_libraries')->onDelete('cascade');
});
Schema::table('accounts', function ($table) {
Schema::table('companies', function ($table) {
$table->string('custom_label1')->nullable();
$table->string('custom_value1')->nullable();
@ -442,7 +492,7 @@ class CreateUsersTable extends Migration
$table->string('custom_value2')->nullable();
});
Schema::table('accounts', function ($table) {
Schema::table('companies', function ($table) {
$table->string('vat_number')->nullable();
});
@ -450,7 +500,7 @@ class CreateUsersTable extends Migration
$table->string('vat_number')->nullable();
});
Schema::table('accounts', function ($table) {
Schema::table('companies', function ($table) {
$table->string('id_number')->nullable();
});
@ -461,7 +511,7 @@ class CreateUsersTable extends Migration
Schema::create('tasks', function ($table) {
$table->increments('id');
$table->unsignedInteger('user_id');
$table->unsignedInteger('account_id')->index();
$table->unsignedInteger('company_id')->index();
$table->unsignedInteger('client_id')->nullable();
$table->unsignedInteger('invoice_id')->nullable();
$table->timestamps();
@ -472,7 +522,7 @@ class CreateUsersTable extends Migration
$table->boolean('is_running')->default(false);
$table->text('time_log')->nullable();
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade');
$table->foreign('client_id')->references('id')->on('clients')->onDelete('cascade');
@ -487,9 +537,9 @@ class CreateUsersTable extends Migration
$table->text('config');
});
Schema::create('bank_accounts', function ($table) {
Schema::create('bank_companies', function ($table) {
$table->increments('id');
$table->unsignedInteger('account_id');
$table->unsignedInteger('company_id');
$table->unsignedInteger('bank_id');
$table->unsignedInteger('user_id');
$table->string('username');
@ -497,18 +547,18 @@ class CreateUsersTable extends Migration
$table->timestamps();
$table->softDeletes();
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foreign('bank_id')->references('id')->on('banks');
});
Schema::create('bank_subaccounts', function ($table) {
Schema::create('bank_subcompanies', function ($table) {
$table->increments('id');
$table->unsignedInteger('account_id');
$table->unsignedInteger('company_id');
$table->unsignedInteger('user_id');
$table->unsignedInteger('bank_account_id');
$table->unsignedInteger('bank_company_id');
$table->string('account_name');
$table->string('account_number');
@ -516,9 +566,9 @@ class CreateUsersTable extends Migration
$table->timestamps();
$table->softDeletes();
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foreign('bank_account_id')->references('id')->on('bank_accounts')->onDelete('cascade');
$table->foreign('bank_company_id')->references('id')->on('bank_companies')->onDelete('cascade');
});
@ -532,29 +582,7 @@ class CreateUsersTable extends Migration
public function down()
{
Schema::dropIfExists('bank_subaccounts');
Schema::dropIfExists('bank_accounts');
Schema::dropIfExists('banks');
Schema::dropIfExists('payment_libraries');
Schema::dropIfExists('languages');
Schema::dropIfExists('payments');
Schema::dropIfExists('products');
Schema::dropIfExists('invitations');
Schema::dropIfExists('tax_rates');
Schema::dropIfExists('invoices');
Schema::dropIfExists('countries');
Schema::dropIfExists('payment_types');
Schema::dropIfExists('timezones');
Schema::dropIfExists('currencies');
Schema::dropIfExists('sizes');
Schema::dropIfExists('industries');
Schema::dropIfExists('gateways');
Schema::dropIfExists('contacts');
Schema::dropIfExists('clients');
Schema::dropIfExists('account_gateways');
Schema::dropIfExists('user_accounts');
Schema::dropIfExists('users');
Schema::dropIfExists('accounts');
}

View File

@ -1,63 +0,0 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddDbToUserTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('db', 100);
});
Schema::table('contacts', function (Blueprint $table) {
$table->string('db', 100);
});
Schema::table('users', function (Blueprint $table){
$table->dropColumn('confirmed');
$table->dropColumn('registered');
});
Schema::table('contacts', function (Blueprint $table){
$table->dropColumn('confirmed');
$table->dropColumn('registered');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('db');
});
Schema::table('contacts', function (Blueprint $table) {
$table->dropColumn('db');
});
Schema::table('users', function (Blueprint $table){
$table->boolean('confirmed');
$table->boolean('registered');
});
Schema::table('contacts', function (Blueprint $table){
$table->boolean('confirmed');
$table->boolean('registered');
});
}
}

View File

@ -55,6 +55,7 @@
</form>
</div>
</div>
@env('hosted')
<div class="card text-white bg-primary py-5 d-md-down-none" style="width:44%">
<div class="card-body text-center">
<div>
@ -64,6 +65,7 @@
</div>
</div>
</div>
@endenv
</div>
</div>
</div>

View File

@ -1,47 +1,53 @@
@extends('layouts.app')
@extends('layouts.master')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Reset Password') }}</div>
@section('body')
<div class="card-body">
@if (session('status'))
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
@endif
<form method="POST" action="{{ route('password.email') }}">
@csrf
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" value="{{ old('email') }}" required>
@if ($errors->has('email'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('email') }}</strong>
<body class="app flex-row align-items-center">
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card-group">
<div class="card p-4">
<div class="card-body">
@if (session('status'))
<div class="alert alert-success" role="alert">
{{ session('status') }}
</div>
@endif
<form method="POST" action="{{ route('password.email') }}">
@csrf
<h1>@lang('texts.password_recovery')</h1>
<p class="text-muted"></p>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">
<i class="icon-user"></i>
</span>
@endif
</div>
</div>
</div>
<input id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" value="{{ old('email') }}" placeholder="@lang('texts.email')" required autofocus>
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Send Password Reset Link') }}
</button>
</div>
@if ($errors->has('email'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif
</div>
<div class="row">
<div class="col-6">
<button class="btn btn-primary px-4" type="submit">@lang('texts.send_email')</button>
</div>
</div>
</form>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@endsection
</body>
</html>

View File

@ -1,65 +1,73 @@
@extends('layouts.app')
@extends('layouts.master')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Reset Password') }}</div>
@section('body')
<div class="card-body">
<form method="POST" action="{{ route('password.update') }}">
@csrf
<input type="hidden" name="token" value="{{ $token }}">
<div class="form-group row">
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
<div class="col-md-6">
<input id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" value="{{ $email ?? old('email') }}" required autofocus>
@if ($errors->has('email'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('email') }}</strong>
<body class="app flex-row align-items-center">
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card-group">
<div class="card p-4">
<div class="card-body">
<form method="POST" action="{{ route('password.update') }}">
@csrf
<input type="hidden" name="token" value="{{ $token }}">
<h1>@lang('texts.change_password')</h1>
<p class="text-muted"></p>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">
<i class="icon-user"></i>
</span>
@endif
</div>
</div>
</div>
<input id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" value="{{ old('email') }}" placeholder="@lang('texts.email')" required autofocus>
<div class="form-group row">
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
<div class="col-md-6">
<input id="password" type="password" class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" required>
@if ($errors->has('password'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('password') }}</strong>
@if ($errors->has('email'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('email') }}</strong>
</span>
@endif
</div>
</div>
@endif
<div class="form-group row">
<label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>
</div>
<div class="col-md-6">
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required>
</div>
</div>
<div class="input-group mb-4">
<div class="input-group-prepend">
<span class="input-group-text">
<i class="icon-lock"></i>
</span>
</div>
<input id="password" type="password" class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" placeholder="@lang('texts.password')" required>
<div class="form-group row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ __('Reset Password') }}
</button>
</div>
@if ($errors->has('password'))
<span class="invalid-feedback" role="alert">
<strong>{{ $errors->first('password') }}</strong>
</span>
@endif
</div>
<div class="input-group mb-4">
<div class="input-group-prepend">
<span class="input-group-text">
<i class="icon-lock"></i>
</span>
</div>
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" placeholder="@lang('texts.confirm_password')" required>
</div>
<div class="row">
<div class="col-6">
<button class="btn btn-primary px-4" type="submit">@lang('texts.change_password')</button>
</div>
</div>
</form>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@endsection
</body>
</html>

View File

@ -79,7 +79,7 @@
<li class="nav-item dropdown">
<a class="nav-link" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
<img class="img-avatar" src="images/logo.png" alt="admin@bootstrapmaster.com"> {{ auth()->user()->getDisplayName() }}
<img class="img-avatar" src="images/logo.png" alt="admin@bootstrapmaster.com"> {{ auth()->user()->present()->name }}
</a>
<div class="dropdown-menu dropdown-menu-right">
<!-- if multiple accounts exist, loop through here and display

View File

@ -57,7 +57,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/simple-line-icons/2.4.1/css/simple-line-icons.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css">
<link rel="canonical" href="{{ config('ninja.app_url') }}/{{ request()->path() }}"/>
<link rel="canonical" href="{{ config('ninja.site_url') }}/{{ request()->path() }}"/>
<link rel="stylesheet" href="{{ mix('/css/ninja.css') }}">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>

View File

@ -13,8 +13,8 @@ Route::post('logout', 'Auth\LoginController@logout')->name('logout');
*/
Route::redirect('/', '/login', 301);
Route::get('signup', 'SignupController@signup')->name('signup');
Route::post('process_signup', 'SignupController@processSignup')->name('signup.submit');
Route::get('signup', 'CompanyController@index')->name('signup');
Route::post('signup', 'CompanyController@store')->name('signup.submit');
Route::get('contact/login', 'Auth\ContactLoginController@showLoginForm')->name('contact.login');
Route::post('contact/login', 'Auth\ContactLoginController@login')->name('contact.login.submit');

View File

@ -3,6 +3,8 @@
namespace Tests\Unit;
use App\Libraries\MultiDB;
use App\Models\Account;
use App\Models\Company;
use App\Models\User;
use Illuminate\Foundation\Testing\Concerns\InteractsWithDatabase;
use Illuminate\Support\Facades\DB;
@ -31,16 +33,33 @@ class MultiDBUserTest extends TestCase
User::unguard();
$ac = factory(\App\Models\Account::class)->make();
$account = Account::on('db-ninja-1')->create($ac->toArray());
$account2 = Account::on('db-ninja-2')->create($ac->toArray());
$company = factory(\App\Models\Company::class)->make([
'account_id' => $account->id,
]);
$company2 = factory(\App\Models\Company::class)->make([
'account_id' => $account2->id,
]);
Company::on('db-ninja-1')->create($company->toArray());
Company::on('db-ninja-2')->create($company2->toArray());
$user = [
'first_name' => 'user_db_1',
'last_name' => 'user_db_1-s',
'phone' => '55555',
'first_name' => 'user_db_1',
'last_name' => 'user_db_1-s',
'phone' => '55555',
'email_verified_at' => now(),
'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
'remember_token' => str_random(10),
'email' => 'db1@example.com',
'oauth_user_id' => '123',
'db' => config('database.default')
'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
'remember_token' => str_random(10),
'email' => 'db1@example.com',
'oauth_user_id' => '123',
'db' => config('database.default'),
'account_id' => $account->id,
];
@ -53,7 +72,8 @@ class MultiDBUserTest extends TestCase
'remember_token' => str_random(10),
'email' => 'db2@example.com',
'oauth_user_id' => 'abc',
'db' => config('database.default')
'db' => config('database.default'),
'account_id' => $account2->id,
];

View File

@ -4,8 +4,9 @@ namespace Tests\Unit;
use App\Http\ValidationRules\UniqueUserRule;
use App\Models\User;
use App\Models\Account;
use App\Models\Company;
use Illuminate\Foundation\Testing\Concerns\InteractsWithDatabase;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Tests\TestCase;
@ -33,16 +34,41 @@ class UniqueEmailTest extends TestCase
$this->rule = new UniqueUserRule();
$user = [
'first_name' => 'user_db_1',
'email' => 'user@example.com',
'password' => Hash::make('password'),
'db' => config('database.default')
$ac = factory(\App\Models\Account::class)->make();
$account = Account::on('db-ninja-1')->create($ac->toArray());
$account2 = Account::on('db-ninja-2')->create($ac->toArray());
$company = factory(\App\Models\Company::class)->make([
'account_id' => $account->id,
]);
$company2 = factory(\App\Models\Company::class)->make([
'account_id' => $account2->id,
]);
Company::on('db-ninja-1')->create($company->toArray());
Company::on('db-ninja-2')->create($company2->toArray());
$user = [
'first_name' => 'user_db_1',
'email' => 'user@example.com',
'password' => Hash::make('password'),
'db' => config('database.default'),
'account_id' => $account->id,
];
$user2 = [
'first_name' => 'user_db_2',
'email' => 'user@example.com',
'password' => Hash::make('password'),
'db' => config('database.default'),
'account_id' => $account2->id,
];
User::on('db-ninja-1')->create($user);
User::on('db-ninja-2')->create($user);
User::on('db-ninja-2')->create($user2);
}