diff --git a/app/Constants.php b/app/Constants.php index a597eb32880f..3e2abd22e70c 100644 --- a/app/Constants.php +++ b/app/Constants.php @@ -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); -} \ No newline at end of file diff --git a/app/Http/Controllers/CompanyController.php b/app/Http/Controllers/CompanyController.php new file mode 100644 index 000000000000..d543c6dc2b22 --- /dev/null +++ b/app/Http/Controllers/CompanyController.php @@ -0,0 +1,105 @@ +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) + { + // + } +} diff --git a/app/Http/Controllers/SignupController.php b/app/Http/Controllers/SignupController.php deleted file mode 100644 index cfafbb2a59c5..000000000000 --- a/app/Http/Controllers/SignupController.php +++ /dev/null @@ -1,84 +0,0 @@ -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'); - - } - -} \ No newline at end of file diff --git a/app/Jobs/RegisterNewAccount.php b/app/Jobs/RegisterNewAccount.php new file mode 100644 index 000000000000..19c75dfc0ccb --- /dev/null +++ b/app/Jobs/RegisterNewAccount.php @@ -0,0 +1,81 @@ +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; + } +} diff --git a/app/Libraries/OAuth.php b/app/Libraries/OAuth.php index 83bed7fbc82e..6584fb0755d6 100644 --- a/app/Libraries/OAuth.php +++ b/app/Libraries/OAuth.php @@ -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; + } + } } \ No newline at end of file diff --git a/app/Models/Account.php b/app/Models/Account.php index c863e1173b88..1d6bf97f83db 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -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(); - } - } diff --git a/app/Models/Company.php b/app/Models/Company.php new file mode 100644 index 000000000000..a1783cdadceb --- /dev/null +++ b/app/Models/Company.php @@ -0,0 +1,161 @@ +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(); + } + +} diff --git a/app/Models/Invitation.php b/app/Models/Invitation.php index 0ba2004f3bcb..c6c82f65a12b 100644 --- a/app/Models/Invitation.php +++ b/app/Models/Invitation.php @@ -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'); + } + } diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index cbc8919f2312..44b2a5aa561c 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -7,4 +7,9 @@ use Illuminate\Database\Eloquent\Model; class Invoice extends Model { // + + public function invitations() + { + $this->morphMany(Invitation::class, 'inviteable'); + } } diff --git a/app/Models/Payments.php b/app/Models/Payment.php similarity index 73% rename from app/Models/Payments.php rename to app/Models/Payment.php index 73c285daeaa3..69de9cab2625 100644 --- a/app/Models/Payments.php +++ b/app/Models/Payment.php @@ -4,7 +4,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; -class Payments extends Model +class Payment extends Model { // } diff --git a/app/Models/Presenters/AccountPresenter.php b/app/Models/Presenters/AccountPresenter.php new file mode 100644 index 000000000000..92c13b518229 --- /dev/null +++ b/app/Models/Presenters/AccountPresenter.php @@ -0,0 +1,14 @@ +entity->first_name . ' ' . $this->entity->last_name; + } + +} diff --git a/app/Models/Proposal.php b/app/Models/Proposal.php new file mode 100644 index 000000000000..f2a8668b874c --- /dev/null +++ b/app/Models/Proposal.php @@ -0,0 +1,16 @@ +morphMany(Invitation::class, 'inviteable'); + } + +} diff --git a/app/Models/Traits/AccountTrait.php b/app/Models/Traits/AccountTrait.php deleted file mode 100644 index 50ae723263a3..000000000000 --- a/app/Models/Traits/AccountTrait.php +++ /dev/null @@ -1,18 +0,0 @@ -name) { - return $this->name; - } - - $user = $this->users()->first(); - - return $user->getDisplayName(); - } -} \ No newline at end of file diff --git a/app/Models/Traits/UserTrait.php b/app/Models/Traits/UserTrait.php deleted file mode 100644 index aeb850cc79cf..000000000000 --- a/app/Models/Traits/UserTrait.php +++ /dev/null @@ -1,34 +0,0 @@ -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 ''; - } - } - -} \ No newline at end of file diff --git a/app/Models/User.php b/app/Models/User.php index 973ba05f94b6..9e8c2c4f9bfe 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -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. * diff --git a/app/Models/UserAccount.php b/app/Models/UserCompany.php similarity index 71% rename from app/Models/UserAccount.php rename to app/Models/UserCompany.php index 9ccdb2b9b112..5946ee351e36 100644 --- a/app/Models/UserAccount.php +++ b/app/Models/UserCompany.php @@ -4,7 +4,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; -class UserAccount extends Model +class UserCompany extends Model { // } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 35471f6ff156..380458a57e22 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -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; + }); } /** diff --git a/composer.json b/composer.json index f384023ed07a..314eb481e424 100644 --- a/composer.json +++ b/composer.json @@ -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", diff --git a/composer.lock b/composer.lock index af02136fca2d..892f5534b1bd 100644 --- a/composer.lock +++ b/composer.lock @@ -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", diff --git a/config/database.php b/config/database.php index f3e2d213ccb1..f1c1467cce5d 100644 --- a/config/database.php +++ b/config/database.php @@ -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' => [ diff --git a/config/ninja.php b/config/ninja.php index a5420ca0adca..79eaa7cae311 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -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'), + ], + ]; diff --git a/database/factories/AccountFactory.php b/database/factories/AccountFactory.php new file mode 100644 index 000000000000..15da56048fe3 --- /dev/null +++ b/database/factories/AccountFactory.php @@ -0,0 +1,9 @@ +define(App\Models\Account::class, function (Faker $faker) { + return [ + // + ]; +}); diff --git a/database/factories/CompanyFactory.php b/database/factories/CompanyFactory.php new file mode 100644 index 000000000000..13dbe0d86e9d --- /dev/null +++ b/database/factories/CompanyFactory.php @@ -0,0 +1,11 @@ +define(App\Models\Company::class, function (Faker $faker) { + return [ + 'name' => $faker->name, + 'company_key' => strtolower(str_random(RANDOM_KEY_LENGTH)), + 'ip' => $faker->ipv4 + ]; +}); diff --git a/database/migrations/2014_10_13_000000_create_users_table.php b/database/migrations/2014_10_13_000000_create_users_table.php index 0542b508f7fa..738cfb3f166f 100644 --- a/database/migrations/2014_10_13_000000_create_users_table.php +++ b/database/migrations/2014_10_13_000000_create_users_table.php @@ -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'); + } diff --git a/database/migrations/2018_10_18_210819_add_db_to_user_table.php b/database/migrations/2018_10_18_210819_add_db_to_user_table.php deleted file mode 100644 index c6eb1450b055..000000000000 --- a/database/migrations/2018_10_18_210819_add_db_to_user_table.php +++ /dev/null @@ -1,63 +0,0 @@ -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'); - - }); - } -} diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index df6ca42d9fb3..72b8fcd079fe 100644 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -55,6 +55,7 @@ + @env('hosted')