diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index af9c7ee4464e..a0b10ff12c8a 100755 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -35,7 +35,7 @@ public function index() : View | RedirectResponse $counts['license'] = \App\Models\License::assetcount(); $counts['consumable'] = \App\Models\Consumable::count(); $counts['component'] = \App\Models\Component::count(); - $counts['user'] = \App\Models\Company::scopeCompanyables(auth()->user())->count(); + $counts['user'] = \App\Models\User::count(); //\App\Models\Company::scopeCompanyables(auth()->user())->count(); $counts['grand_total'] = $counts['asset'] + $counts['accessory'] + $counts['license'] + $counts['consumable']; if ((! file_exists(storage_path().'/oauth-private.key')) || (! file_exists(storage_path().'/oauth-public.key'))) { diff --git a/app/Http/Controllers/Licenses/LicensesController.php b/app/Http/Controllers/Licenses/LicensesController.php index 6098423ba3e6..b60666d87af4 100755 --- a/app/Http/Controllers/Licenses/LicensesController.php +++ b/app/Http/Controllers/Licenses/LicensesController.php @@ -317,8 +317,8 @@ public function getExportLicensesCsv() 'supplier', 'adminuser', 'assignedusers') - ->orderBy('created_at', 'DESC'); - Company::scopeCompanyables($licenses) + ->orderBy('created_at', 'DESC') //; + //Company::scopeCompanyables($licenses) ->chunk(500, function ($licenses) use ($handle) { $headers = [ // strtolower to prevent Excel from trying to open it as a SYLK file diff --git a/app/Models/Accessory.php b/app/Models/Accessory.php index fc1bb36ab40d..ff1f775c61c5 100755 --- a/app/Models/Accessory.php +++ b/app/Models/Accessory.php @@ -4,6 +4,7 @@ use App\Helpers\Helper; use App\Models\Traits\Acceptable; +use App\Models\Traits\Companyable; use App\Models\Traits\Searchable; use App\Presenters\Presentable; use Illuminate\Database\Eloquent\Factories\HasFactory; @@ -21,7 +22,7 @@ class Accessory extends SnipeModel use HasFactory; protected $presenter = \App\Presenters\AccessoryPresenter::class; - use CompanyableTrait; + use Companyable; use Loggable, Presentable; use SoftDeletes; diff --git a/app/Models/Actionlog.php b/app/Models/Actionlog.php index 008c5b11462c..715baf6714fc 100755 --- a/app/Models/Actionlog.php +++ b/app/Models/Actionlog.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\Traits\Companyable; use App\Models\Traits\Searchable; use App\Presenters\Presentable; use Carbon\Carbon; @@ -16,7 +17,7 @@ */ class Actionlog extends SnipeModel { - use CompanyableTrait; + use Companyable; use HasFactory; // This is to manually set the source (via setActionSource()) for determineActionSource() diff --git a/app/Models/Asset.php b/app/Models/Asset.php index ce8b870eb2e0..848e630e3045 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -7,19 +7,17 @@ use App\Helpers\Helper; use App\Http\Traits\UniqueUndeletedTrait; use App\Models\Traits\Acceptable; +use App\Models\Traits\Companyable; use App\Models\Traits\Searchable; -use App\Presenters\Presentable; use App\Presenters\AssetPresenter; -use Illuminate\Support\Facades\Auth; +use App\Presenters\Presentable; use Carbon\Carbon; -use Illuminate\Support\Facades\DB; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Facades\Storage; use Watson\Validating\ValidatingTrait; -use Illuminate\Database\Eloquent\Casts\Attribute; -use Illuminate\Database\Eloquent\Model; /** * Model for Assets. @@ -32,7 +30,7 @@ class Asset extends Depreciable protected $presenter = AssetPresenter::class; protected $with = ['model', 'adminuser']; - use CompanyableTrait; + use Companyable; use HasFactory, Loggable, Requestable, Presentable, SoftDeletes, ValidatingTrait, UniqueUndeletedTrait; public const LOCATION = 'location'; @@ -1437,7 +1435,7 @@ public function scopeRequestableAssets($query) { $table = $query->getModel()->getTable(); - return Company::scopeCompanyables($query->where($table.'.requestable', '=', 1)) + return $query->where($table.'.requestable', '=', 1) // TODO Companyable removed here ->whereHas('assetstatus', function ($query) { $query->where(function ($query) { $query->where('deployable', '=', 1) diff --git a/app/Models/AssetMaintenance.php b/app/Models/AssetMaintenance.php index 246220f5c7a3..956605ab7a61 100644 --- a/app/Models/AssetMaintenance.php +++ b/app/Models/AssetMaintenance.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Helpers\Helper; +use App\Models\Traits\CompanyableChild; use App\Models\Traits\Searchable; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; @@ -18,7 +19,7 @@ class AssetMaintenance extends Model implements ICompanyableChild { use HasFactory; use SoftDeletes; - use CompanyableChildTrait; + use CompanyableChild; use ValidatingTrait; diff --git a/app/Models/Company.php b/app/Models/Company.php index 8886da77f6c0..7dc7c01c479b 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -242,104 +242,11 @@ public function components() return $this->hasMany(Component::class, 'company_id'); } - /** - * START COMPANY SCOPING FOR FMCS - */ - - /** - * Scoping table queries, determining if a logged in user is part of a company, and only allows the user to access items associated with that company if FMCS is enabled. - * - * This method is the one that the CompanyableTrait uses to contrain queries automatically, however that trait CANNOT be - * applied to the user's model, since it causes an infinite loop against the authenticated user. - * - * @todo - refactor that trait to handle the user's model as well. - * - * @author [A. Gianotto] - * @param $query - * @param $column - * @param $table_name - * @return mixed - */ - public static function scopeCompanyables($query, $column = 'company_id', $table_name = null) - { - // If not logged in and hitting this, assume we are on the command line and don't scope?' - if (! static::isFullMultipleCompanySupportEnabled() || (Auth::hasUser() && auth()->user()->isSuperUser()) || (! Auth::hasUser())) { - return $query; - } else { - return static::scopeCompanyablesDirectly($query, $column, $table_name); - } - } - - /** - * Scoping table queries, determining if a logged-in user is part of a company, and only allows - * that user to see items associated with that company - * - * @see https://github.com/laravel/framework/pull/24518 for info on Auth::hasUser() - */ - private static function scopeCompanyablesDirectly($query, $column = 'company_id', $table_name = null) - { - - // Get the company ID of the logged-in user, or set it to null if there is no company associated with the user - if (Auth::hasUser()) { - $company_id = auth()->user()->company_id; - } else { - $company_id = null; - } - - - // If the column exists in the table, use it to scope the query - if ((($query) && ($query->getModel()) && (Schema::hasColumn($query->getModel()->getTable(), $column)))) { - - // Dynamically get the table name if it's not passed in, based on the model we're querying against - $table = ($table_name) ? $table_name."." : $query->getModel()->getTable()."."; - - return $query->where($table.$column, '=', $company_id); - } - - } - public function adminuser() { return $this->belongsTo(\App\Models\User::class, 'created_by'); } - - /** - * I legit do not know what this method does, but we can't remove it (yet). - * - * This gets invoked by CompanyableChildScope, but I'm not sure what it does. - * - * @author [A. Gianotto] - * @param array $companyable_names - * @param $query - * @return mixed - */ - public static function scopeCompanyableChildren(array $companyable_names, $query) - { - - if (count($companyable_names) == 0) { - throw new Exception('No Companyable Children to scope'); - } elseif (! static::isFullMultipleCompanySupportEnabled() || (Auth::hasUser() && auth()->user()->isSuperUser())) { - return $query; - } else { - $f = function ($q) { - Log::debug('scopeCompanyablesDirectly firing '); - static::scopeCompanyablesDirectly($q); - }; - - $q = $query->where(function ($q) use ($companyable_names, $f) { - $q2 = $q->whereHas($companyable_names[0], $f); - - for ($i = 1; $i < count($companyable_names); $i++) { - $q2 = $q2->orWhereHas($companyable_names[$i], $f); - } - }); - - return $q; - } - } - - /** * Query builder scope to order on the user that created it */ diff --git a/app/Models/CompanyableChildScope.php b/app/Models/CompanyableChildScope.php deleted file mode 100644 index 4077ebd596bf..000000000000 --- a/app/Models/CompanyableChildScope.php +++ /dev/null @@ -1,40 +0,0 @@ -getModel(); - - return Company::scopeCompanyableChildren($model->getCompanyableParents(), $builder); - } - - /** - * @todo IMPLEMENT - * Remove the scope from the given Eloquent query builder. - * - * @param \Illuminate\Database\Eloquent\Builder $builder - * @return void - */ - public function remove(Builder $builder) - { - } -} diff --git a/app/Models/CompanyableChildTrait.php b/app/Models/CompanyableChildTrait.php deleted file mode 100644 index 1158c70e98ba..000000000000 --- a/app/Models/CompanyableChildTrait.php +++ /dev/null @@ -1,16 +0,0 @@ -assets()->withoutGlobalScope(new CompanyableScope)->get() as $checkout) { + foreach ($this->assets()->withoutGlobalScope('companyable')->get() as $checkout) { $checkedout += $checkout->pivot->assigned_qty; } diff --git a/app/Models/Consumable.php b/app/Models/Consumable.php index 30161e84296a..7b735a44cfec 100644 --- a/app/Models/Consumable.php +++ b/app/Models/Consumable.php @@ -4,28 +4,22 @@ use App\Helpers\Helper; use App\Models\Traits\Acceptable; +use App\Models\Traits\Companyable; use App\Models\Traits\Searchable; +use App\Presenters\ConsumablePresenter; use App\Presenters\Presentable; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Facades\Storage; use Watson\Validating\ValidatingTrait; -use Illuminate\Database\Eloquent\Relations\Relation; -use App\Presenters\ConsumablePresenter; -use App\Models\Actionlog; -use App\Models\ConsumableAssignment; -use App\Models\User; -use App\Models\Location; -use App\Models\Manufacturer; -use App\Models\Supplier; -use App\Models\Category; class Consumable extends SnipeModel { use HasFactory; protected $presenter = ConsumablePresenter::class; - use CompanyableTrait; + use Companyable; use Loggable, Presentable; use SoftDeletes; use Acceptable; diff --git a/app/Models/ConsumableAssignment.php b/app/Models/ConsumableAssignment.php index 4c9a19703e5b..5db83ea2ad23 100644 --- a/app/Models/ConsumableAssignment.php +++ b/app/Models/ConsumableAssignment.php @@ -2,12 +2,13 @@ namespace App\Models; +use App\Models\Traits\Companyable; use Illuminate\Database\Eloquent\Model; use Watson\Validating\ValidatingTrait; class ConsumableAssignment extends Model { - use CompanyableTrait; + use Companyable; use ValidatingTrait; protected $table = 'consumables_users'; diff --git a/app/Models/Department.php b/app/Models/Department.php index 855cb25f64df..dc8bd2c9817e 100644 --- a/app/Models/Department.php +++ b/app/Models/Department.php @@ -3,13 +3,14 @@ namespace App\Models; use App\Http\Traits\UniqueUndeletedTrait; +use App\Models\Traits\Companyable; use App\Models\Traits\Searchable; use Illuminate\Database\Eloquent\Factories\HasFactory; use Watson\Validating\ValidatingTrait; class Department extends SnipeModel { - use CompanyableTrait; + use Companyable; use HasFactory; /** diff --git a/app/Models/License.php b/app/Models/License.php index 0997c1e57b99..05469b09e8a2 100755 --- a/app/Models/License.php +++ b/app/Models/License.php @@ -3,13 +3,13 @@ namespace App\Models; use App\Helpers\Helper; +use App\Models\Traits\Companyable; use App\Models\Traits\Searchable; use App\Presenters\Presentable; use Carbon\Carbon; -use Illuminate\Support\Facades\DB; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\SoftDeletes; -use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Session; use Watson\Validating\ValidatingTrait; @@ -20,7 +20,7 @@ class License extends Depreciable protected $presenter = \App\Presenters\LicensePresenter::class; use SoftDeletes; - use CompanyableTrait; + use Companyable; use Loggable, Presentable; protected $injectUniqueIdentifier = true; use ValidatingTrait; diff --git a/app/Models/LicenseSeat.php b/app/Models/LicenseSeat.php index 397a14146870..b1a03d1d84ab 100755 --- a/app/Models/LicenseSeat.php +++ b/app/Models/LicenseSeat.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Models\Traits\Acceptable; +use App\Models\Traits\CompanyableChild; use App\Notifications\CheckinLicenseNotification; use App\Notifications\CheckoutLicenseNotification; use App\Presenters\Presentable; @@ -11,7 +12,7 @@ class LicenseSeat extends SnipeModel implements ICompanyableChild { - use CompanyableChildTrait; + use CompanyableChild; use HasFactory; use Loggable; use SoftDeletes; diff --git a/app/Models/Traits/Companyable.php b/app/Models/Traits/Companyable.php new file mode 100644 index 000000000000..47a5473f80fd --- /dev/null +++ b/app/Models/Traits/Companyable.php @@ -0,0 +1,41 @@ +getModel(); + // If not logged in and hitting this, assume we are on the command line and don't scope?' + if (!Setting::getSettings()?->full_multiple_companies_support || (Auth::hasUser() && auth()->user()->isSuperUser()) || (!Auth::hasUser())) { + return $builder; + } else { + // Get the company ID of the logged-in user, or set it to null if there is no company associated with the user + if (Auth::hasUser()) { + $company_id = auth()->user()->company_id; + } else { + $company_id = null; + } + + // If the column exists in the table, use it to scope the query + if (Schema::hasColumn($model->getTable(), 'company_id')) { + return $builder->where($model->getTable().".company_id", '=', $company_id); + } + } + }); + } +} \ No newline at end of file diff --git a/app/Models/Traits/CompanyableChild.php b/app/Models/Traits/CompanyableChild.php new file mode 100644 index 000000000000..02beb1694059 --- /dev/null +++ b/app/Models/Traits/CompanyableChild.php @@ -0,0 +1,57 @@ +getModel(); + + $companyable_names = $model->getCompanyableParents(); + if (count($companyable_names) == 0) { + throw new \Exception('No Companyable Children to scope'); + } elseif (!Setting::getSettings()?->full_multiple_companies_support || (Auth::hasUser() && auth()->user()->isSuperUser())) { + return $builder; + } else { + if (Auth::hasUser()) { + $company_id = auth()->user()->company_id; + } else { + $company_id = null; + } + + $q = $builder->where(function ($q) use ($companyable_names, $company_id) { + // helper function to look for company_id *if* you have one + $company_if_needed = function ($subquery) use ($company_id) { + $table = $subquery->getModel()->getTable(); + if (Schema::hasColumn($table, 'company_id')) { + $subquery->where($table.'.company_id', $company_id); + } + }; + + //first, handle the *first* of the companyable_names... + $q2 = $q->whereHas($companyable_names[0], $company_if_needed); + + //then, go through the list of the remaining, appending them on to the query with 'orWhereHas()' + for ($i = 1; $i < count($companyable_names); $i++) { + $q2 = $q2->orWhereHas($companyable_names[$i], $company_if_needed); + } + }); + + return $q; + } + + }); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 5b3d8768273f..a54e28b79e7a 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Http\Traits\UniqueUndeletedTrait; +use App\Models\Traits\Companyable; use App\Models\Traits\Searchable; use App\Presenters\Presentable; use Illuminate\Auth\Authenticatable; @@ -23,7 +24,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract, HasLocalePreference { use HasFactory; - use CompanyableTrait; + use Companyable; protected $presenter = \App\Presenters\UserPresenter::class; use SoftDeletes, ValidatingTrait;