Merge pull request #11005 from turbo124/v5-develop

v5.11.80
This commit is contained in:
David Bomba 2025-05-28 09:04:18 +10:00 committed by GitHub
commit e446f9f2f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
44 changed files with 430 additions and 231 deletions

View File

@ -1 +1 @@
5.11.79 5.11.80

View File

@ -57,8 +57,9 @@ class S3Cleanup extends Command
$c1 = Company::on('db-ninja-01')->pluck('company_key'); $c1 = Company::on('db-ninja-01')->pluck('company_key');
$c2 = Company::on('db-ninja-02')->pluck('company_key'); $c2 = Company::on('db-ninja-02')->pluck('company_key');
$c3 = Company::on('db-ninja-03')->pluck('company_key');
$merged = $c1->merge($c2)->toArray(); $merged = $c1->merge($c2)->merge($c3)->toArray();
$directories = Storage::disk(config('filesystems.default'))->directories(); $directories = Storage::disk(config('filesystems.default'))->directories();

View File

@ -172,8 +172,7 @@ class InvoiceItemExport extends BaseExport
$tmp_key = str_replace("item.", "", $key); $tmp_key = str_replace("item.", "", $key);
if ($tmp_key == 'tax_id') { if ($tmp_key == 'tax_id') {
// $tmp_key = 'tax_category'; $item_array[$key] = $this->getTaxCategoryName((int)$item->tax_id ?? 1); // @phpstan-ignore-line
$item_array[$key] = $this->getTaxCategoryName((int)$item->tax_id);
} }
elseif (property_exists($item, $tmp_key)) { elseif (property_exists($item, $tmp_key)) {
$item_array[$key] = $item->{$tmp_key}; $item_array[$key] = $item->{$tmp_key};

View File

@ -296,6 +296,20 @@ class InvoiceFilters extends QueryFilters
return $this->builder->orderByRaw("REGEXP_REPLACE(invoices.number,'[^0-9]+','')+0 " . $dir); return $this->builder->orderByRaw("REGEXP_REPLACE(invoices.number,'[^0-9]+','')+0 " . $dir);
} }
if ($sort_col[0] == 'status_id') {
// Special handling for status_id==2 (STATUS_SENT) with sub-statuses
return $this->builder->orderByRaw("
CASE
WHEN status_id != 2 THEN status_id
WHEN status_id = 2 AND (due_date IS NOT NULL AND (due_date < NOW() OR partial_due_date < NOW())) THEN 2.9
WHEN status_id = 2 AND last_viewed IS NOT NULL THEN 2.5
WHEN status_id = 2 THEN 2.2
ELSE status_id
END " . $dir);
}
return $this->builder->orderBy("{$this->builder->getQuery()->from}.".$sort_col[0], $dir); return $this->builder->orderBy("{$this->builder->getQuery()->from}.".$sort_col[0], $dir);
} }

View File

@ -104,7 +104,7 @@ class AccountController extends BaseController
$cu = CompanyUser::query()->where('user_id', $account->users()->first()->id); $cu = CompanyUser::query()->where('user_id', $account->users()->first()->id);
$company_user = $cu->first(); $company_user = $cu->first();
$truth = app()->make(TruthSource::class); $truth = app()->make(TruthSource::class);
$truth->setCompanyUser($company_user); $truth->setCompanyUser($company_user);
$truth->setUser($company_user->user); $truth->setUser($company_user->user);

View File

@ -122,7 +122,7 @@ class ContactResetPasswordController extends Controller
event(new PasswordReset($user)); event(new PasswordReset($user));
auth()->login($user, true); auth()->login($user, false);
$response = Password::PASSWORD_RESET; $response = Password::PASSWORD_RESET;

View File

@ -280,7 +280,7 @@ class LoginController extends BaseController
return response()->json(['message' => 'User exists, but not attached to any companies! Orphaned user!'], 400); return response()->json(['message' => 'User exists, but not attached to any companies! Orphaned user!'], 400);
} }
Auth::login($existing_user, true); Auth::login($existing_user, false);
/** @var \App\Models\CompanyUser $cu */ /** @var \App\Models\CompanyUser $cu */
$cu = $this->hydrateCompanyUser(); $cu = $this->hydrateCompanyUser();
@ -301,7 +301,7 @@ class LoginController extends BaseController
return response()->json(['message' => 'User exists, but not attached to any companies! Orphaned user!'], 400); return response()->json(['message' => 'User exists, but not attached to any companies! Orphaned user!'], 400);
} }
Auth::login($existing_login_user, true); Auth::login($existing_login_user, false);
/** @var \App\Models\User $user */ /** @var \App\Models\User $user */
$user = auth()->user(); $user = auth()->user();
@ -352,7 +352,7 @@ class LoginController extends BaseController
$account = (new CreateAccount($new_account, request()->getClientIp()))->handle(); $account = (new CreateAccount($new_account, request()->getClientIp()))->handle();
Auth::login($account->default_company->owner(), true); Auth::login($account->default_company->owner(), false);
/** @var \App\Models\User $user */ /** @var \App\Models\User $user */
$user = auth()->user(); $user = auth()->user();
@ -456,17 +456,6 @@ class LoginController extends BaseController
return response()->json(['message' => 'User exists, but never authenticated with OAuth, please use your email and password to login.'], 400); return response()->json(['message' => 'User exists, but never authenticated with OAuth, please use your email and password to login.'], 400);
} }
// If this is a result user/email combo - lets add their OAuth details details
// if ($email && $existing_login_user = MultiDB::hasUser(['email' => $email, 'oauth_provider_id' => 'microsoft'])) {
// if (!$existing_login_user->account) {
// return response()->json(['message' => 'User exists, but not attached to any companies! Orphaned user!'], 400);
// }
// Auth::login($existing_login_user, true);
// return $this->existingLoginUser($user->getId(), 'microsoft');
// }
// Signup! // Signup!
if (request()->has('create') && request()->input('create') == 'true') { if (request()->has('create') && request()->input('create') == 'true') {
$new_account = [ $new_account = [
@ -496,7 +485,7 @@ class LoginController extends BaseController
*/ */
private function existingOauthUser($existing_user) private function existingOauthUser($existing_user)
{ {
Auth::login($existing_user, true); Auth::login($existing_user, false);
/** @var \App\Models\CompanyUser $cu */ /** @var \App\Models\CompanyUser $cu */
$cu = $this->hydrateCompanyUser(); $cu = $this->hydrateCompanyUser();
@ -569,17 +558,7 @@ class LoginController extends BaseController
return response()->json(['message' => 'Please use your email and password to login.'], 400); return response()->json(['message' => 'Please use your email and password to login.'], 400);
} }
// 2025-05-19 - this caused an issue when a user/email password combo user used their google account to login, it raced through and attempted to create a new account.
//If this is a result user/email combo - lets add their OAuth details details
// if ($existing_login_user = MultiDB::hasUser(['email' => $google->harvestEmail($user), 'oauth_provider_id' => 'google'])) {
// if (!$existing_login_user->account) {
// return response()->json(['message' => 'User exists, but not attached to any companies! Orphaned user!'], 400);
// }
// Auth::login($existing_login_user, true);
// return $this->existingLoginUser($google->harvestSubField($user), 'google');
// }
} }
if ($user) { if ($user) {
@ -589,7 +568,7 @@ class LoginController extends BaseController
return response()->json(['message' => 'User exists, but not attached to any companies! Orphaned user!'], 400); return response()->json(['message' => 'User exists, but not attached to any companies! Orphaned user!'], 400);
} }
Auth::login($existing_login_user, true); Auth::login($existing_login_user, false);
return $this->existingLoginUser($google->harvestSubField($user), 'google'); return $this->existingLoginUser($google->harvestSubField($user), 'google');
} }
@ -628,7 +607,7 @@ class LoginController extends BaseController
return $account; return $account;
} }
Auth::login($account->default_company->owner(), true); Auth::login($account->default_company->owner(), false);
/** @var \App\Models\User $user */ /** @var \App\Models\User $user */
$user = auth()->user(); $user = auth()->user();

View File

@ -12,51 +12,52 @@
namespace App\Http; namespace App\Http;
use App\Http\Middleware\ApiSecretCheck; use App\Http\Middleware\Cors;
use App\Http\Middleware\SetDb;
use App\Http\Middleware\Locale;
use App\Http\Middleware\SetWebDb;
use App\Http\Middleware\UrlSetDb;
use App\Http\Middleware\TokenAuth;
use App\Http\Middleware\SetEmailDb;
use App\Http\Middleware\VerifyHash;
use App\Http\Middleware\SetInviteDb;
use App\Http\Middleware\TrimStrings;
use App\Http\Middleware\Authenticate; use App\Http\Middleware\Authenticate;
use App\Http\Middleware\CheckClientExistence; use App\Http\Middleware\ContactSetDb;
use App\Http\Middleware\CheckForMaintenanceMode; use App\Http\Middleware\QueryLogging;
use App\Http\Middleware\ClientPortalEnabled; use App\Http\Middleware\TrustProxies;
use App\Http\Middleware\UserVerified;
use App\Http\Middleware\VendorLocale;
use App\Http\Middleware\PhantomSecret;
use App\Http\Middleware\SetDocumentDb;
use App\Http\Middleware\ApiSecretCheck;
use App\Http\Middleware\ContactAccount; use App\Http\Middleware\ContactAccount;
use App\Http\Middleware\EncryptCookies;
use App\Http\Middleware\SessionDomains;
use App\Http\Middleware\ContactKeyLogin; use App\Http\Middleware\ContactKeyLogin;
use App\Http\Middleware\ContactRegister; use App\Http\Middleware\ContactRegister;
use App\Http\Middleware\ContactSetDb;
use App\Http\Middleware\ContactTokenAuth;
use App\Http\Middleware\Cors;
use App\Http\Middleware\EncryptCookies;
use App\Http\Middleware\Locale;
use App\Http\Middleware\PasswordProtection;
use App\Http\Middleware\PhantomSecret;
use App\Http\Middleware\QueryLogging;
use App\Http\Middleware\RedirectIfAuthenticated;
use App\Http\Middleware\SessionDomains;
use App\Http\Middleware\SetDbByCompanyKey;
use App\Http\Middleware\SetDocumentDb;
use App\Http\Middleware\SetDomainNameDb; use App\Http\Middleware\SetDomainNameDb;
use App\Http\Middleware\SetEmailDb;
use App\Http\Middleware\SetInviteDb;
use App\Http\Middleware\SetWebDb;
use App\Http\Middleware\TokenAuth;
use App\Http\Middleware\TrimStrings;
use App\Http\Middleware\TrustProxies;
use App\Http\Middleware\UrlSetDb;
use App\Http\Middleware\UserVerified;
use App\Http\Middleware\ValidateSignature;
use App\Http\Middleware\VendorContactKeyLogin;
use App\Http\Middleware\VendorLocale;
use App\Http\Middleware\VerifyCsrfToken; use App\Http\Middleware\VerifyCsrfToken;
use App\Http\Middleware\VerifyHash; use App\Http\Middleware\ContactTokenAuth;
use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;
use Illuminate\Auth\Middleware\Authorize; use Illuminate\Auth\Middleware\Authorize;
use Illuminate\Auth\Middleware\EnsureEmailIsVerified; use App\Http\Middleware\SetDbByCompanyKey;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; use App\Http\Middleware\ValidateSignature;
use Illuminate\Foundation\Http\Kernel as HttpKernel; use App\Http\Middleware\PasswordProtection;
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull; use App\Http\Middleware\ClientPortalEnabled;
use Illuminate\Foundation\Http\Middleware\ValidatePostSize; use App\Http\Middleware\CheckClientExistence;
use App\Http\Middleware\VendorContactKeyLogin;
use Illuminate\Http\Middleware\SetCacheHeaders; use Illuminate\Http\Middleware\SetCacheHeaders;
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Session\Middleware\StartSession; use Illuminate\Session\Middleware\StartSession;
use App\Http\Middleware\CheckForMaintenanceMode;
use App\Http\Middleware\RedirectIfAuthenticated;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
use Illuminate\Auth\Middleware\EnsureEmailIsVerified;
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\View\Middleware\ShareErrorsFromSession; use Illuminate\View\Middleware\ShareErrorsFromSession;
use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;
use Illuminate\Foundation\Http\Middleware\ValidatePostSize;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
class Kernel extends HttpKernel class Kernel extends HttpKernel
{ {
@ -150,6 +151,7 @@ class Kernel extends HttpKernel
'portal_enabled' => ClientPortalEnabled::class, 'portal_enabled' => ClientPortalEnabled::class,
'url_db' => UrlSetDb::class, 'url_db' => UrlSetDb::class,
'web_db' => SetWebDb::class, 'web_db' => SetWebDb::class,
'api_db' => SetDb::class,
'company_key_db' => SetDbByCompanyKey::class, 'company_key_db' => SetDbByCompanyKey::class,
'locale' => Locale::class, 'locale' => Locale::class,
'vendor_locale' => VendorLocale::class, 'vendor_locale' => VendorLocale::class,
@ -172,6 +174,7 @@ class Kernel extends HttpKernel
SessionDomains::class, SessionDomains::class,
Cors::class, Cors::class,
SetDomainNameDb::class, SetDomainNameDb::class,
SetDb::class,
SetWebDb::class, SetWebDb::class,
UrlSetDb::class, UrlSetDb::class,
ContactSetDb::class, ContactSetDb::class,

View File

@ -0,0 +1,48 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2025. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Http\Middleware;
use App\Libraries\MultiDB;
use Closure;
use Illuminate\Http\Request;
use stdClass;
class SetDb
{
/**
* Handle an incoming request.
*
* @param Request $request
* @param Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$error = [
'message' => 'Invalid Token',
'errors' => new stdClass(),
];
if ($request->header('X-API-TOKEN') && config('ninja.db.multi_db_enabled')) {
if (! MultiDB::findAndSetDb($request->header('X-API-TOKEN'))) {
return response()->json($error, 403);
}
} elseif (! config('ninja.db.multi_db_enabled')) {
return $next($request);
} else {
return response()->json($error, 403);
}
return $next($request);
}
}

View File

@ -32,17 +32,18 @@ class TokenAuth
*/ */
public function handle($request, Closure $next) public function handle($request, Closure $next)
{ {
if (config('ninja.db.multi_db_enabled') &&
$request->header('X-API-TOKEN') && if ($request->header('X-API-TOKEN') && ($company_token = CompanyToken::with([
($company_token = MultiDB::getCompanyToken($request->header('X-API-TOKEN')))) {
} elseif ($request->header('X-API-TOKEN') && ($company_token = CompanyToken::with([
'user.account', 'user.account',
'company', 'company',
'account', 'account',
'cu',
])->where('token', $request->header('X-API-TOKEN'))->first())) { ])->where('token', $request->header('X-API-TOKEN'))->first())) {
} else { } else {
return response()->json(['message' => 'Invalid token'], 403); return response()->json(['message' => 'Invalid token'], 403);
} }
$user = $company_token->user; $user = $company_token->user;
$error = [ $error = [
@ -83,7 +84,6 @@ class TokenAuth
*/ */
app('queue')->createPayloadUsing(function () use ($company_token) { app('queue')->createPayloadUsing(function () use ($company_token) {
return ['db' => $company_token->company->db]; return ['db' => $company_token->company->db];
// return ['db' => $company_token->company->db, 'is_premium' => $company_token->account->isPremium()];
}); });
//user who once existed, but has been soft deleted //user who once existed, but has been soft deleted

View File

@ -84,7 +84,7 @@ class BaseImport
) )
: null; : null;
auth()->login($this->company->owner(), true); auth()->login($this->company->owner(), false);
/** @var \App\Models\User $user */ /** @var \App\Models\User $user */
$user = auth()->user(); $user = auth()->user();

View File

@ -51,13 +51,13 @@ class CreateAccount
public function handle() public function handle()
{ {
if (config('ninja.environment') == 'selfhost' && Account::count() == 0) { // if (config('ninja.environment') == 'selfhost' && Account::count() == 0) {
return $this->create(); // return $this->create();
} elseif (config('ninja.environment') == 'selfhost' && Account::count() > 1) { // } elseif (config('ninja.environment') == 'selfhost' && Account::count() > 1) {
return response()->json(['message' => Ninja::selfHostedMessage()], 400); // return response()->json(['message' => Ninja::selfHostedMessage()], 400);
} elseif (! Ninja::boot()) { // } elseif (! Ninja::boot()) {
return response()->json(['message' => Ninja::parse()], 401); // return response()->json(['message' => Ninja::parse()], 401);
} // }
return $this->create(); return $this->create();
} }
@ -115,6 +115,7 @@ class CreateAccount
event(new AccountCreated($spaa9f78, $sp035a66, Ninja::eventVars())); event(new AccountCreated($spaa9f78, $sp035a66, Ninja::eventVars()));
} }
$spaa9f78->fresh(); $spaa9f78->fresh();
if (Ninja::isHosted()) { if (Ninja::isHosted()) {

View File

@ -29,11 +29,12 @@ class WebhookHandler implements ShouldQueue
use Queueable; use Queueable;
use SerializesModels; use SerializesModels;
public $tries = 1; //number of retries public $tries = 1; //number of retries
public $timeout = 30;
public $deleteWhenMissingModels = true; public $deleteWhenMissingModels = true;
/** /**
* Create a new job instance. * Create a new job instance.
* *
@ -66,6 +67,11 @@ class WebhookHandler implements ShouldQueue
}); });
} }
public function viaQueue()
{
return \App\Utils\Ninja::isHosted() ? 'webhooks' : 'default';
}
public function failed($exception = null) public function failed($exception = null)
{ {
} }

View File

@ -208,7 +208,7 @@ class MultiDB
foreach (self::$dbs as $db) { foreach (self::$dbs as $db) {
self::setDB($db); self::setDB($db);
if ($user = User::where($data)->withTrashed()->first()) { if ($user = User::on($db)->where($data)->withTrashed()->first()) {
return $user; return $user;
} }
} }
@ -653,7 +653,7 @@ class MultiDB
foreach (self::$dbs as $db) { foreach (self::$dbs as $db) {
self::setDB($db); self::setDB($db);
if ($exists = Account::where('account_sms_verification_number', $phone)->where('account_sms_verified', true)->exists()) { if ($exists = Account::on($db)->where('account_sms_verification_number', $phone)->where('account_sms_verified', true)->exists()) {
self::setDb($current_db); self::setDb($current_db);
return true; return true;
} }

View File

@ -310,7 +310,7 @@ class Account extends BaseModel
} }
// 09-03-2023 - winds forward expiry checks to ensure we don't cut off users prior to billing cycle being commenced // 09-03-2023 - winds forward expiry checks to ensure we don't cut off users prior to billing cycle being commenced
if ($this->plan_expires && Carbon::parse($this->plan_expires)->lt(now()->subHours(12))) { if ($this->plan_expires && Carbon::parse($this->plan_expires)->lt(now()->subHours(23))) {
return false; return false;
} }

View File

@ -12,7 +12,7 @@
namespace App\Models; namespace App\Models;
use Laravel\Scout\Searchable; use Elastic\ScoutDriverPlus\Searchable;
use App\DataMapper\ClientSync; use App\DataMapper\ClientSync;
use App\Utils\Traits\AppSetup; use App\Utils\Traits\AppSetup;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;

View File

@ -14,7 +14,7 @@ namespace App\Models;
use App\Utils\Ninja; use App\Utils\Ninja;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Laravel\Scout\Searchable; use Elastic\ScoutDriverPlus\Searchable;
use App\Jobs\Mail\NinjaMailer; use App\Jobs\Mail\NinjaMailer;
use App\Utils\Traits\AppSetup; use App\Utils\Traits\AppSetup;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;

View File

@ -84,9 +84,7 @@ class CompanyToken extends BaseModel
public function company_user(): \Illuminate\Database\Eloquent\Relations\HasOne public function company_user(): \Illuminate\Database\Eloquent\Relations\HasOne
{ {
return $this->hasOne(CompanyUser::class, 'user_id', 'user_id') return $this->hasOne(CompanyUser::class, ['user_id', 'company_id'], ['user_id', 'company_id']);
->where('company_id', $this->company_id)
->where('user_id', $this->user_id);
} }
/** /**
@ -94,8 +92,24 @@ class CompanyToken extends BaseModel
*/ */
public function cu() public function cu()
{ {
return $this->hasOne(CompanyUser::class, 'user_id', 'user_id') return $this->hasOne(CompanyUser::class, ['user_id', 'company_id'], ['user_id', 'company_id']);
->where('company_id', $this->company_id)
->where('user_id', $this->user_id);
} }
// public function company_user(): \Illuminate\Database\Eloquent\Relations\HasOne
// {
// return $this->hasOne(CompanyUser::class, 'user_id', 'user_id')
// ->where('company_id', $this->company_id)
// ->where('user_id', $this->user_id);
// }
// /**
// * @return \Awobaz\Compoships\Database\Eloquent\Relations\HasOne
// */
// public function cu()
// {
// return $this->hasOne(CompanyUser::class, 'user_id', 'user_id')
// ->where('company_id', $this->company_id)
// ->where('user_id', $this->user_id);
// }
} }

View File

@ -14,7 +14,7 @@ namespace App\Models;
use App\Utils\Ninja; use App\Utils\Ninja;
use App\Utils\Number; use App\Utils\Number;
use Laravel\Scout\Searchable; use Elastic\ScoutDriverPlus\Searchable;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use App\Helpers\Invoice\InvoiceSum; use App\Helpers\Invoice\InvoiceSum;

View File

@ -153,6 +153,7 @@ class CreditInvitation extends BaseModel
public function markViewed() public function markViewed()
{ {
$this->viewed_date = Carbon::now(); $this->viewed_date = Carbon::now();
$this->credit->last_viewed = Carbon::now();
$this->save(); $this->save();
} }

View File

@ -13,7 +13,7 @@
namespace App\Models; namespace App\Models;
use App\Utils\Number; use App\Utils\Number;
use Laravel\Scout\Searchable; use Elastic\ScoutDriverPlus\Searchable;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;

View File

@ -271,7 +271,7 @@ class Invoice extends BaseModel
'custom_value4' => (string)$this->custom_value4, 'custom_value4' => (string)$this->custom_value4,
'company_key' => $this->company->company_key, 'company_key' => $this->company->company_key,
'po_number' => (string)$this->po_number, 'po_number' => (string)$this->po_number,
'line_items' => $this->line_items, // 'line_items' => $this->line_items,
]; ];
} }

View File

@ -148,6 +148,7 @@ class InvoiceInvitation extends BaseModel
public function markViewed(): void public function markViewed(): void
{ {
$this->viewed_date = Carbon::now(); $this->viewed_date = Carbon::now();
$this->invoice->last_viewed = Carbon::now();
$this->save(); $this->save();
} }

View File

@ -14,7 +14,7 @@ namespace App\Models;
use App\Utils\Ninja; use App\Utils\Ninja;
use App\Utils\Number; use App\Utils\Number;
use Laravel\Scout\Searchable; use Elastic\ScoutDriverPlus\Searchable;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use App\Helpers\Invoice\InvoiceSum; use App\Helpers\Invoice\InvoiceSum;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;

View File

@ -139,6 +139,7 @@ class PurchaseOrderInvitation extends BaseModel
public function markViewed(): void public function markViewed(): void
{ {
$this->viewed_date = Carbon::now(); $this->viewed_date = Carbon::now();
$this->purchase_order->last_viewed = Carbon::now();
$this->save(); $this->save();
} }

View File

@ -15,7 +15,7 @@ namespace App\Models;
use App\Utils\Ninja; use App\Utils\Ninja;
use App\Utils\Number; use App\Utils\Number;
use App\DataMapper\QuoteSync; use App\DataMapper\QuoteSync;
use Laravel\Scout\Searchable; use Elastic\ScoutDriverPlus\Searchable;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use App\Helpers\Invoice\InvoiceSum; use App\Helpers\Invoice\InvoiceSum;

View File

@ -139,6 +139,7 @@ class QuoteInvitation extends BaseModel
public function markViewed() public function markViewed()
{ {
$this->viewed_date = Carbon::now(); $this->viewed_date = Carbon::now();
$this->quote->last_viewed = Carbon::now();
$this->save(); $this->save();
} }

View File

@ -13,7 +13,7 @@
namespace App\Models; namespace App\Models;
use App\Utils\Number; use App\Utils\Number;
use Laravel\Scout\Searchable; use Elastic\ScoutDriverPlus\Searchable;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use App\Helpers\Invoice\InvoiceSum; use App\Helpers\Invoice\InvoiceSum;

View File

@ -12,7 +12,7 @@
namespace App\Models; namespace App\Models;
use Laravel\Scout\Searchable; use Elastic\ScoutDriverPlus\Searchable;
use App\Utils\Traits\AppSetup; use App\Utils\Traits\AppSetup;
use App\DataMapper\CompanySettings; use App\DataMapper\CompanySettings;
use Illuminate\Support\Facades\App; use Illuminate\Support\Facades\App;

View File

@ -12,7 +12,7 @@
namespace App\Models; namespace App\Models;
use Laravel\Scout\Searchable; use Elastic\ScoutDriverPlus\Searchable;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Cache;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;

View File

@ -80,6 +80,7 @@ class AuthorizeCreditCard implements LivewireMethodInterface
if ($request->has('store_card') && $request->input('store_card') === true) { if ($request->has('store_card') && $request->input('store_card') === true) {
$authorise_payment_method = new AuthorizePaymentMethod($this->authorize); $authorise_payment_method = new AuthorizePaymentMethod($this->authorize);
$authorise_payment_method->setPaymentMethodId(\App\Models\GatewayType::CREDIT_CARD);
$payment_profile = $authorise_payment_method->addPaymentMethodToClient($gateway_customer_reference, $data); $payment_profile = $authorise_payment_method->addPaymentMethodToClient($gateway_customer_reference, $data);
$payment_profile_id = $payment_profile->getPaymentProfile()->getCustomerPaymentProfileId(); $payment_profile_id = $payment_profile->getPaymentProfile()->getCustomerPaymentProfileId();
@ -233,7 +234,7 @@ class AuthorizeCreditCard implements LivewireMethodInterface
private function processSuccessfulResponse($data, $request) private function processSuccessfulResponse($data, $request)
{ {
$payment_hash = PaymentHash::where('hash', $request->input('payment_hash'))->firstOrFail(); $payment_hash = PaymentHash::where('hash', $request->input('payment_hash'))->firstOrFail();
$payment = $this->storePayment($payment_hash, $data); $payment = $this->storePayment($payment_hash, $data, \App\Models\GatewayType::CREDIT_CARD);
$vars = [ $vars = [
'invoices' => $payment_hash->invoices(), 'invoices' => $payment_hash->invoices(),

View File

@ -39,6 +39,12 @@ class AuthorizePaymentMethod
private $payment_method_id; private $payment_method_id;
public function setPaymentMethodId($payment_method_id)
{
$this->payment_method_id = $payment_method_id;
return $this;
}
public function __construct(AuthorizePaymentDriver $authorize) public function __construct(AuthorizePaymentDriver $authorize)
{ {
$this->authorize = $authorize; $this->authorize = $authorize;

View File

@ -83,10 +83,9 @@ class AppServiceProvider extends ServiceProvider
/* Ensure we don't have stale state in jobs */ /* Ensure we don't have stale state in jobs */
Queue::before(function (JobProcessing $event) { Queue::before(function (JobProcessing $event) {
App::forgetInstance('truthsource'); App::forgetInstance(TruthSource::class);
}); });
/* Always init a new instance everytime the container boots */
app()->instance(TruthSource::class, new TruthSource()); app()->instance(TruthSource::class, new TruthSource());
/* Extension for custom mailers */ /* Extension for custom mailers */
@ -155,5 +154,6 @@ class AppServiceProvider extends ServiceProvider
public function register(): void public function register(): void
{ {
} }
} }

View File

@ -119,7 +119,7 @@ class ActivityRepository extends BaseRepository
public function getTokenId(array $event_vars) public function getTokenId(array $event_vars)
{ {
if ($event_vars['token']) { if (isset($event_vars['token']) &&$event_vars['token']) {
/** @var \App\Models\CompanyToken $company_token **/ /** @var \App\Models\CompanyToken $company_token **/
$company_token = CompanyToken::query()->where('token', $event_vars['token'])->first(); $company_token = CompanyToken::query()->where('token', $event_vars['token'])->first();

View File

@ -92,7 +92,7 @@ class UserRepository extends BaseRepository
/*No company user exists - attach the user*/ /*No company user exists - attach the user*/
if (! $cu) { if (! $cu) {
$data['company_user']['account_id'] = $account->id; $data['company_user']['account_id'] = $account->id;
$data['company_user']['notifications'] = CompanySettings::notificationDefaults(); $data['company_user']['notifications'] = isset($data['company_user']['notifications']['email']) ? $data['company_user']['notifications'] : CompanySettings::notificationDefaults();
$user->companies()->attach($company->id, $data['company_user']); $user->companies()->attach($company->id, $data['company_user']);
} else { } else {
if (auth()->user()->isAdmin()) { if (auth()->user()->isAdmin()) {

View File

@ -226,8 +226,8 @@
"url": "https://github.com/turbo124/snappdf" "url": "https://github.com/turbo124/snappdf"
}, },
{ {
"type": "path", "type": "vcs",
"url": "../admin-api" "url": "https://github.com/invoiceninja/admin-api"
} }
], ],
"minimum-stability": "dev", "minimum-stability": "dev",

2
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "4361272676d998d08fb1926198065b39", "content-hash": "4c133d6a99108c7c4e779dfdab4457e3",
"packages": [ "packages": [
{ {
"name": "adrienrn/php-mimetyper", "name": "adrienrn/php-mimetyper",

View File

@ -17,8 +17,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true), 'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
'app_version' => env('APP_VERSION', '5.11.79'), 'app_version' => env('APP_VERSION', '5.11.80'),
'app_tag' => env('APP_TAG', '5.11.79'), 'app_tag' => env('APP_TAG', '5.11.80'),
'minimum_client_version' => '5.0.16', 'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1', 'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', false), 'api_secret' => env('API_SECRET', false),

View File

@ -20,6 +20,7 @@ parameters:
- 'app/PaymentDrivers/AuthorizePaymentDriver.php' - 'app/PaymentDrivers/AuthorizePaymentDriver.php'
- 'app/Http/Middleware/ThrottleRequestsWithPredis.php' - 'app/Http/Middleware/ThrottleRequestsWithPredis.php'
- 'app/Utils/Traits/*' - 'app/Utils/Traits/*'
- 'Modules/Accounting/*'
universalObjectCratesClasses: universalObjectCratesClasses:
- App\DataMapper\Tax\RuleInterface - App\DataMapper\Tax\RuleInterface
- App\DataMapper\FeesAndLimits - App\DataMapper\FeesAndLimits

View File

@ -139,7 +139,7 @@ Route::group(['middleware' => ['throttle:login', 'api_secret_check', 'email_db']
Route::post('api/v1/reset_password', [ForgotPasswordController::class, 'sendResetLinkEmail']); Route::post('api/v1/reset_password', [ForgotPasswordController::class, 'sendResetLinkEmail']);
}); });
Route::group(['middleware' => ['throttle:api', 'token_auth', 'valid_json','locale'], 'prefix' => 'api/v1', 'as' => 'api.'], function () { Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'valid_json','locale'], 'prefix' => 'api/v1', 'as' => 'api.'], function () {
Route::post('password_timeout', PasswordTimeoutController::class)->name('password_timeout'); Route::post('password_timeout', PasswordTimeoutController::class)->name('password_timeout');
Route::put('accounts/{account}', [AccountController::class, 'update'])->name('account.update'); Route::put('accounts/{account}', [AccountController::class, 'update'])->name('account.update');

View File

@ -45,7 +45,7 @@ class CsvImportTest extends TestCase
$this->withoutExceptionHandling(); $this->withoutExceptionHandling();
auth()->login($this->user); // auth()->login($this->user);
} }
public function testRecurringInvoiceImport() public function testRecurringInvoiceImport()
@ -119,6 +119,8 @@ class CsvImportTest extends TestCase
Cache::put($hash.'-recurring_invoice', base64_encode($csv), 360); Cache::put($hash.'-recurring_invoice', base64_encode($csv), 360);
// $this->user->setContext($this->company, $this->token);
$truth = app()->make(TruthSource::class); $truth = app()->make(TruthSource::class);
$truth->setCompanyUser($this->cu); $truth->setCompanyUser($this->cu);
$truth->setUser($this->user); $truth->setUser($this->user);
@ -355,10 +357,12 @@ class CsvImportTest extends TestCase
Cache::put($hash.'-invoice', base64_encode($csv), 360); Cache::put($hash.'-invoice', base64_encode($csv), 360);
$truth = app()->make(TruthSource::class); // $this->user->setContext($this->company, $this->token);
$truth->setCompanyUser($this->cu);
$truth->setUser($this->user); // $truth = app()->make(TruthSource::class);
$truth->setCompany($this->company); // $truth->setCompanyUser($this->cu);
// $truth->setUser($this->user);
// $truth->setCompany($this->company);
$csv_importer = new Csv($data, $this->company); $csv_importer = new Csv($data, $this->company);

View File

@ -11,22 +11,24 @@
namespace Tests\Feature; namespace Tests\Feature;
use App\DataMapper\CompanySettings; use Tests\TestCase;
use App\Factory\CompanyUserFactory; use App\Models\User;
use App\Http\Middleware\PasswordProtection;
use App\Models\Account; use App\Models\Account;
use App\Models\Company; use App\Models\Company;
use App\Models\CompanyToken; use App\Libraries\MultiDB;
use App\Utils\TruthSource;
use Tests\MockAccountData;
use App\Models\CompanyUser; use App\Models\CompanyUser;
use App\Models\User; use App\Models\CompanyToken;
use App\DataMapper\CompanySettings;
use App\Factory\CompanyUserFactory;
use App\Repositories\UserRepository; use App\Repositories\UserRepository;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Support\Facades\Session; use Illuminate\Support\Facades\Session;
use App\Http\Middleware\PasswordProtection;
use Illuminate\Validation\ValidationException; use Illuminate\Validation\ValidationException;
use Tests\MockAccountData; use Illuminate\Routing\Middleware\ThrottleRequests;
use Tests\TestCase; use Illuminate\Foundation\Testing\DatabaseTransactions;
/** /**
* *
@ -35,7 +37,6 @@ use Tests\TestCase;
class UserTest extends TestCase class UserTest extends TestCase
{ {
use MockAccountData; use MockAccountData;
use DatabaseTransactions;
private $default_email = 'attach@gmail.com'; private $default_email = 'attach@gmail.com';
@ -52,7 +53,7 @@ class UserTest extends TestCase
PasswordProtection::class PasswordProtection::class
); );
$this->makeTestData(); // $this->makeTestData();
// $this->withoutExceptionHandling(); // $this->withoutExceptionHandling();
@ -73,9 +74,14 @@ class UserTest extends TestCase
'account_id' => $account->id, 'account_id' => $account->id,
'confirmation_code' => 'xyz123', 'confirmation_code' => 'xyz123',
'email' => $this->faker->unique()->safeEmail(), 'email' => $this->faker->unique()->safeEmail(),
'password' => \Illuminate\Support\Facades\Hash::make('ALongAndBriliantPassword'),
]); ]);
$user->password = \Illuminate\Support\Facades\Hash::make('ALongAndBriliantPassword');
$user->email_verified_at = now();
$user->save();
auth()->login($user, false);
$settings = CompanySettings::defaults(); $settings = CompanySettings::defaults();
$settings->client_online_payment_notification = false; $settings->client_online_payment_notification = false;
$settings->client_manual_payment_notification = false; $settings->client_manual_payment_notification = false;
@ -85,11 +91,21 @@ class UserTest extends TestCase
'settings' => $settings, 'settings' => $settings,
]); ]);
$cu = CompanyUserFactory::create($user->id, $company->id, $account->id); // $cu = CompanyUserFactory::create($user->id, $company->id, $account->id);
$cu->is_owner = true; // $cu->is_owner = true;
$cu->is_admin = true; // $cu->is_admin = true;
$cu->is_locked = false; // $cu->is_locked = false;
$cu->save(); // $cu->save();
$user->companies()->attach($company->id, [
'account_id' => $account->id,
'is_owner' => 1,
'is_admin' => 1,
'is_locked' => 0,
'permissions' => '',
'notifications' => \App\DataMapper\CompanySettings::notificationAdminDefaults(),
'settings' => null,
]);
$token = \Illuminate\Support\Str::random(64); $token = \Illuminate\Support\Str::random(64);
@ -102,55 +118,31 @@ class UserTest extends TestCase
$company_token->is_system = true; $company_token->is_system = true;
$company_token->save(); $company_token->save();
// auth()->user()->setContext($company, $company_token);
$truth = app()->make(TruthSource::class);
$truth->setCompanyUser($company_token->cu);
$truth->setUser($company_token->user);
$truth->setCompany($company_token->company);
$truth->setCompanyToken($company_token);
return $company_token; return $company_token;
} }
// public function testCrossAccountFunctionality()
// {
// $ct = $this->mockAccount();
// $u= $ct->user;
// auth()->login($u, true);
// $account = Account::factory()->create([
// 'hosted_client_count' => 1000,
// 'hosted_company_count' => 1000,
// ]);
// $account->num_users = 3;
// $account->save();
// $user = User::factory()->create([
// 'account_id' => $this->account->id,
// 'confirmation_code' => 'xyz123',
// 'email' => $this->faker->unique()->safeEmail(),
// 'password' => \Illuminate\Support\Facades\Hash::make('ALongAndBriliantPassword'),
// ]);
// $user_repo = new UserRepository();
// // try{
// $x = $user_repo->save(['first_name' => 'bobby'], $user);
// // }
// // catch(\Exception $e){
// // $this->assertEquals(401, $e->getCode());
// // }
// nlog($x);
// }
public function testValidEmailUpdate() public function testValidEmailUpdate()
{ {
$company_token = $this->mockAccount(); $company_token = $this->mockAccount();
$user = $company_token->user; $user = auth()->user();
$user->load('company_user');
// $user = $company_token->user;
// $user->load('company_user');
// nlog($company_token->toArray());
// $user = User::with('company_user')->find($company_token->user_id);
// nlog($user->toArray());
$data = $user->toArray(); $data = $user->toArray();
@ -162,6 +154,19 @@ class UserTest extends TestCase
$response->assertStatus(200); $response->assertStatus(200);
$data['email'] = 'newemail@gmail.com';
// $response = $this->withHeaders([
// 'X-API-SECRET' => config('ninja.api_secret'),
// 'X-API-TOKEN' => $company_token->token,
// 'X-API-PASSWORD' => 'ALongAndBriliantPassword',
// ])->putJson('/api/v1/users/'.$user->hashed_id.'?include=company_user', $data);
// $response->assertStatus(200);
// $data = $response->json();
// $this->assertEquals($data['data']['email'], $data['email']);
} }
@ -169,9 +174,11 @@ class UserTest extends TestCase
{ {
$company_token = $this->mockAccount(); $company_token = $this->mockAccount();
$user = $company_token->user; // $user = $company_token->user;
$user->load('company_user'); // $user->load('company_user');
$user = auth()->user();
$data = $user->toArray(); $data = $user->toArray();
$data['email'] = ''; $data['email'] = '';
unset($data['password']); unset($data['password']);
@ -215,14 +222,19 @@ class UserTest extends TestCase
public function testUserLocale() public function testUserLocale()
{ {
$this->user->language_id = "13";
$this->user->save(); $company_token = $this->mockAccount();
$this->assertEquals("fr_CA", $this->user->getLocale()); $user = auth()->user();
$user->language_id = "13";
$user->save();
$this->assertEquals("fr_CA", $user->getLocale());
$response = $this->withHeaders([ $response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'), 'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token, 'X-API-TOKEN' => $company_token->token,
])->get('/api/v1/statics'); ])->get('/api/v1/statics');
$response->assertStatus(200); $response->assertStatus(200);
@ -235,6 +247,12 @@ class UserTest extends TestCase
{ {
$company_token = $this->mockAccount(); $company_token = $this->mockAccount();
$_user = MultiDB::hasUser(['email' => 'normal_user@gmail.com']);
if($_user) {
$_user->account->delete();
}
$data = [ $data = [
'first_name' => 'hey', 'first_name' => 'hey',
'last_name' => 'you', 'last_name' => 'you',
@ -337,7 +355,7 @@ class UserTest extends TestCase
$account->save(); $account->save();
$user = User::factory()->create([ $user = User::factory()->create([
'account_id' => $this->account->id, 'account_id' => $account->id,
'confirmation_code' => 'xyz123', 'confirmation_code' => 'xyz123',
'email' => $this->faker->unique()->safeEmail(), 'email' => $this->faker->unique()->safeEmail(),
'password' => \Illuminate\Support\Facades\Hash::make('ALongAndBriliantPassword'), 'password' => \Illuminate\Support\Facades\Hash::make('ALongAndBriliantPassword'),
@ -352,12 +370,15 @@ class UserTest extends TestCase
'settings' => $settings, 'settings' => $settings,
]); ]);
$user->companies()->attach($company->id, [
$cu = CompanyUserFactory::create($user->id, $company->id, $account->id); 'account_id' => $account->id,
$cu->is_owner = true; 'is_owner' => 1,
$cu->is_admin = true; 'is_admin' => 1,
$cu->is_locked = false; 'is_locked' => 0,
$cu->save(); 'permissions' => '',
'notifications' => \App\DataMapper\CompanySettings::notificationAdminDefaults(),
'settings' => null,
]);
$token = \Illuminate\Support\Str::random(64); $token = \Illuminate\Support\Str::random(64);
@ -385,45 +406,56 @@ class UserTest extends TestCase
} }
public function testDisconnectUserOauthMailer() // public function testDisconnectUserOauthMailer()
{ // {
$user = // $account = Account::factory()->create([
User::factory()->create([ // 'hosted_client_count' => 1000,
'account_id' => $this->account->id, // 'hosted_company_count' => 1000,
'email' => $this->faker->safeEmail(), // ]);
'oauth_user_id' => '123456789',
'oauth_provider_id' => '123456789',
]);
$response = $this->withHeaders([ // $user =
'X-API-TOKEN' => $this->token, // User::factory()->create([
])->post("/api/v1/users/{$user->hashed_id}/disconnect_mailer"); // 'account_id' => $account->id,
// 'email' => $this->faker->safeEmail(),
// 'oauth_user_id' => '123456789',
// 'oauth_provider_id' => '123456789',
// ]);
$response->assertStatus(200); // $response = $this->withHeaders([
// 'X-API-TOKEN' => $this->token,
// ])->post("/api/v1/users/{$user->hashed_id}/disconnect_mailer");
$user->fresh(); // $response->assertStatus(200);
$this->assertNull($user->oauth_user_token); // $user->fresh();
$this->assertNull($user->oauth_user_refresh_token);
} // $this->assertNull($user->oauth_user_token);
// $this->assertNull($user->oauth_user_refresh_token);
// }
public function testUserFiltersWith() public function testUserFiltersWith()
{ {
$company_token = $this->mockAccount();
$response = $this->withHeaders([ $response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'), 'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token, 'X-API-TOKEN' => $company_token->token,
'X-API-PASSWORD' => 'ALongAndBriliantPassword', 'X-API-PASSWORD' => 'ALongAndBriliantPassword',
])->get('/api/v1/users?with='.$this->user->hashed_id); ])->get('/api/v1/users?with='.$company_token->user->hashed_id);
$response->assertStatus(200); $response->assertStatus(200);
} }
public function testUserList() public function testUserList()
{ {
$company_token = $this->mockAccount();
$response = $this->withHeaders([ $response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'), 'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token, 'X-API-TOKEN' => $company_token->token,
'X-API-PASSWORD' => 'ALongAndBriliantPassword', 'X-API-PASSWORD' => 'ALongAndBriliantPassword',
])->get('/api/v1/users'); ])->get('/api/v1/users');
@ -433,6 +465,13 @@ class UserTest extends TestCase
public function testValidationRulesPhoneIsNull() public function testValidationRulesPhoneIsNull()
{ {
$this->withoutMiddleware(PasswordProtection::class); $this->withoutMiddleware(PasswordProtection::class);
$company_token = $this->mockAccount();
$_user = MultiDB::hasUser(['email' => 'bob1@good.ole.boys.com']);
if ($_user) {
$_user->account->delete();
}
$data = [ $data = [
'first_name' => 'hey', 'first_name' => 'hey',
@ -448,7 +487,7 @@ class UserTest extends TestCase
$response = $this->withHeaders([ $response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'), 'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token, 'X-API-TOKEN' => $company_token->token,
'X-API-PASSWORD' => 'ALongAndBriliantPassword', 'X-API-PASSWORD' => 'ALongAndBriliantPassword',
])->postJson('/api/v1/users?include=company_user', $data); ])->postJson('/api/v1/users?include=company_user', $data);
@ -459,6 +498,13 @@ class UserTest extends TestCase
{ {
$this->withoutMiddleware(PasswordProtection::class); $this->withoutMiddleware(PasswordProtection::class);
$_user = MultiDB::hasUser(['email' => 'bob1@good.ole.boys.com']);
if($_user) {
$_user->account->delete();
}
$company_token = $this->mockAccount();
$data = [ $data = [
'first_name' => 'hey', 'first_name' => 'hey',
'last_name' => 'you', 'last_name' => 'you',
@ -473,7 +519,7 @@ class UserTest extends TestCase
$response = $this->withHeaders([ $response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'), 'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token, 'X-API-TOKEN' => $company_token->token,
'X-API-PASSWORD' => 'ALongAndBriliantPassword', 'X-API-PASSWORD' => 'ALongAndBriliantPassword',
])->postJson('/api/v1/users?include=company_user', $data); ])->postJson('/api/v1/users?include=company_user', $data);
@ -500,7 +546,7 @@ class UserTest extends TestCase
$response = $this->withHeaders([ $response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'), 'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token, 'X-API-TOKEN' => $company_token->token,
'X-API-PASSWORD' => 'ALongAndBriliantPassword', 'X-API-PASSWORD' => 'ALongAndBriliantPassword',
])->putJson('/api/v1/users/'.$user->hashed_id.'?include=company_user', $data); ])->putJson('/api/v1/users/'.$user->hashed_id.'?include=company_user', $data);
} }
@ -509,6 +555,14 @@ class UserTest extends TestCase
{ {
$this->withoutMiddleware(PasswordProtection::class); $this->withoutMiddleware(PasswordProtection::class);
$_user = MultiDB::hasUser(['email' => 'bob1@good.ole.boys.com']);
if($_user) {
$_user->account->delete();
}
$company_token = $this->mockAccount();
$data = [ $data = [
'first_name' => 'hey', 'first_name' => 'hey',
'last_name' => 'you', 'last_name' => 'you',
@ -523,7 +577,7 @@ class UserTest extends TestCase
$response = $this->withHeaders([ $response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'), 'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token, 'X-API-TOKEN' => $company_token->token,
'X-API-PASSWORD' => 'ALongAndBriliantPassword', 'X-API-PASSWORD' => 'ALongAndBriliantPassword',
])->postJson('/api/v1/users?include=company_user', $data); ])->postJson('/api/v1/users?include=company_user', $data);
@ -538,6 +592,13 @@ class UserTest extends TestCase
{ {
$this->withoutMiddleware(PasswordProtection::class); $this->withoutMiddleware(PasswordProtection::class);
$_user = MultiDB::hasUser(['email' => $this->default_email]);
if ($_user) {
$_user->account->delete();
}
$company_token = $this->mockAccount();
$data = [ $data = [
'first_name' => 'Test', 'first_name' => 'Test',
'last_name' => 'Palloni', 'last_name' => 'Palloni',
@ -548,7 +609,7 @@ class UserTest extends TestCase
$response = $this->withHeaders([ $response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'), 'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token, 'X-API-TOKEN' => $company_token->token,
'X-API-PASSWORD' => 'ALongAndBriliantPassword', 'X-API-PASSWORD' => 'ALongAndBriliantPassword',
])->postJson('/api/v1/users?include=company_user', $data); ])->postJson('/api/v1/users?include=company_user', $data);
@ -558,7 +619,7 @@ class UserTest extends TestCase
$response = $this->withHeaders([ $response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'), 'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token, 'X-API-TOKEN' => $company_token->token,
'X-API-PASSWORD' => 'ALongAndBriliantPassword', 'X-API-PASSWORD' => 'ALongAndBriliantPassword',
])->delete('/api/v1/users/'.$arr['data']['id'].'/detach_from_company?include=company_user'); ])->delete('/api/v1/users/'.$arr['data']['id'].'/detach_from_company?include=company_user');
@ -566,8 +627,8 @@ class UserTest extends TestCase
$user_id = $this->decodePrimaryKey($arr['data']['id']); $user_id = $this->decodePrimaryKey($arr['data']['id']);
$cu = CompanyUser::whereUserId($user_id)->whereCompanyId($this->company->id)->first(); $cu = CompanyUser::whereUserId($user_id)->whereCompanyId($company_token->company->id)->first();
$ct = CompanyToken::whereUserId($user_id)->whereCompanyId($this->company->id)->first(); $ct = CompanyToken::whereUserId($user_id)->whereCompanyId($company_token->company->id)->first();
$user = User::find($user_id); $user = User::find($user_id);
$this->assertNull($cu); $this->assertNull($cu);
@ -579,25 +640,46 @@ class UserTest extends TestCase
{ {
$this->withoutMiddleware(PasswordProtection::class); $this->withoutMiddleware(PasswordProtection::class);
$company_token = $this->mockAccount();
$_user = MultiDB::hasUser(['email' => $this->default_email]);
if ($_user) {
$_user->account->delete();
}
$_user = MultiDB::hasUser(['email' => 'bob@good.ole.boys.co2.com']);
if ($_user) {
$_user->account->delete();
}
/* Create New Company */ /* Create New Company */
$company2 = Company::factory()->create([ $company2 = Company::factory()->create([
'account_id' => $this->account->id, 'account_id' => $company_token->account_id,
]); ]);
$company_token = new CompanyToken(); $company_token = new CompanyToken();
$company_token->user_id = $this->user->id; $company_token->user_id = auth()->user()->id;
$company_token->company_id = $company2->id; $company_token->company_id = $company2->id;
$company_token->account_id = $this->account->id; $company_token->account_id = auth()->user()->account_id;
$company_token->name = 'test token'; $company_token->name = 'test token';
$company_token->token = \Illuminate\Support\Str::random(64); $company_token->token = \Illuminate\Support\Str::random(64);
$company_token->is_system = true; $company_token->is_system = true;
$company_token->save(); $company_token->save();
/*Manually link this user to the company*/ /*Manually link this user to the company*/
$cu = CompanyUserFactory::create($this->user->id, $company2->id, $this->account->id); auth()->user()->companies()->attach($company2->id, [
$cu->is_owner = true; 'account_id' => $company_token->account_id,
$cu->is_admin = true; 'is_owner' => 1,
$cu->save(); 'is_admin' => 1,
'is_locked' => 0,
'permissions' => '',
'notifications' => \App\DataMapper\CompanySettings::notificationAdminDefaults(),
'settings' => null,
]);
/*Create New Blank User and Attach to Company 2*/ /*Create New Blank User and Attach to Company 2*/
$data = [ $data = [

View File

@ -35,12 +35,25 @@ class MultiDBUserTest extends TestCase
{ {
parent::setUp(); parent::setUp();
$this->withoutExceptionHandling(); // $this->withoutExceptionHandling();
if (! config('ninja.db.multi_db_enabled')) { if (! config('ninja.db.multi_db_enabled')) {
$this->markTestSkipped('Multi DB not enabled - skipping'); $this->markTestSkipped('Multi DB not enabled - skipping');
} }
foreach(MultiDB::getDBs() as $db) {
MultiDB::setDB($db);
$u = User::where('email','db1@example.com')->first();
if($u)
$u->account->delete();
$u = User::where('email', 'db2@example.com')->first();
if ($u) {
$u->account->delete();
}
}
User::unguard(); User::unguard();
$ac = Account::factory()->make(); $ac = Account::factory()->make();
@ -202,7 +215,7 @@ class MultiDBUserTest extends TestCase
])->postJson('/api/v1/users?include=company_user', $data); ])->postJson('/api/v1/users?include=company_user', $data);
$response->assertStatus(403); $response->assertStatus(422);
} }
@ -241,9 +254,30 @@ class MultiDBUserTest extends TestCase
{ {
parent::tearDown(); parent::tearDown();
DB::connection('db-ninja-01')->table('users')->delete();
DB::connection('db-ninja-02')->table('users')->delete(); $u = User::on('db-ninja-01')->where('email', 'db1@example.com')->first();
if ($u) {
$u->account->delete();
}
config(['database.default' => config('ninja.db.default')]);
$u = User::on('db-ninja-01')->where('email', 'db2@example.com')->first();
if ($u) {
$u->account->delete();
}
$u = User::on('db-ninja-02')->where('email', 'db1@example.com')->first();
if ($u) {
$u->account->delete();
}
$u = User::on('db-ninja-02')->where('email', 'db2@example.com')->first();
if ($u) {
$u->account->delete();
}
} }
} }

View File

@ -272,8 +272,8 @@ trait MockAccountData
$user_id = $user->id; $user_id = $user->id;
$this->user = $user; $this->user = $user;
// auth()->login($user); auth()->login($user, false);
// auth()->user()->setCompany($this->company); auth()->user()->setCompany($this->company);
CreateCompanyTaskStatuses::dispatchSync($this->company, $this->user); CreateCompanyTaskStatuses::dispatchSync($this->company, $this->user);
@ -295,6 +295,8 @@ trait MockAccountData
$company_token->save(); $company_token->save();
// $user->setContext($this->company, $company_token);
$truth = app()->make(TruthSource::class); $truth = app()->make(TruthSource::class);
$truth->setCompanyUser($company_token->first()); $truth->setCompanyUser($company_token->first());
$truth->setUser($this->user); $truth->setUser($this->user);