diff --git a/app/Http/Controllers/Api/UsersController.php b/app/Http/Controllers/Api/UsersController.php index ba1a5366f6..0faa541243 100644 --- a/app/Http/Controllers/Api/UsersController.php +++ b/app/Http/Controllers/Api/UsersController.php @@ -75,8 +75,8 @@ class UsersController extends Controller 'users.autoassign_licenses', 'users.website', - ])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy',) - ->withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count'); + ])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables', 'createdBy') + ->withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count', 'managesUsers as manages_users_count', 'managedLocations as manages_locations_count'); if ($request->filled('activated')) { @@ -187,6 +187,14 @@ class UsersController extends Controller $users->has('accessories', '=', $request->input('accessories_count')); } + if ($request->filled('manages_users_count')) { + $users->has('manages_users_count', '=', $request->input('manages_users_count')); + } + + if ($request->filled('manages_locations_count')) { + $users->has('manages_locations_count', '=', $request->input('manages_locations_count')); + } + if ($request->filled('autoassign_licenses')) { $users->where('autoassign_licenses', '=', $request->input('autoassign_licenses')); } @@ -244,6 +252,8 @@ class UsersController extends Controller 'licenses_count', 'consumables_count', 'accessories_count', + 'manages_user_count', + 'manages_locations_count', 'phone', 'address', 'city', @@ -405,11 +415,15 @@ class UsersController extends Controller { $this->authorize('view', User::class); - $user = User::withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count')->findOrFail($id); - $user = Company::scopeCompanyables($user)->find($id); - $this->authorize('update', $user); + $user = User::withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count', 'managesUsers as manages_users_count', 'managedLocations as manages_locations_count'); + + if ($user = Company::scopeCompanyables($user)->find($id)) { + $this->authorize('view', $user); + return (new UsersTransformer)->transformUser($user); + } + + return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found', compact('id')))); - return (new UsersTransformer)->transformUser($user); } @@ -470,7 +484,6 @@ class UsersController extends Controller } - // Update the location of any assets checked out to this user Asset::where('assigned_type', User::class) ->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]); @@ -480,12 +493,6 @@ class UsersController extends Controller if ($user->save()) { - // Sync group memberships: - // This was changed in Snipe-IT v4.6.x to 4.7, since we upgraded to Laravel 5.5 - // which changes the behavior of has vs filled. - // The $request->has method will now return true even if the input value is an empty string or null. - // A new $request->filled method has was added that provides the previous behavior of the has method. - // Check if the request has groups passed and has a value if ($request->filled('groups')) { diff --git a/app/Http/Middleware/AssetCountForSidebar.php b/app/Http/Middleware/AssetCountForSidebar.php index e529f75efa..9d81eca93f 100644 --- a/app/Http/Middleware/AssetCountForSidebar.php +++ b/app/Http/Middleware/AssetCountForSidebar.php @@ -21,25 +21,36 @@ class AssetCountForSidebar /** * This needs to be set for the /setup process, since the tables might not exist yet */ + $total_assets = 0; $total_due_for_checkin = 0; $total_overdue_for_checkin = 0; $total_due_for_audit = 0; $total_overdue_for_audit = 0; try { - $total_rtd_sidebar = Asset::RTD()->count(); - view()->share('total_rtd_sidebar', $total_rtd_sidebar); + $settings = Setting::getSettings(); + view()->share('settings', $settings); } catch (\Exception $e) { \Log::debug($e); } try { - $total_assets = Asset::RTD()->count(); + $total_assets = Asset::all()->count(); + if ($settings->show_archived_in_list != '1') { + $total_assets -= Asset::Archived()->count(); + } view()->share('total_assets', $total_assets); } catch (\Exception $e) { \Log::debug($e); } + try { + $total_rtd_sidebar = Asset::RTD()->count(); + view()->share('total_rtd_sidebar', $total_rtd_sidebar); + } catch (\Exception $e) { + \Log::debug($e); + } + try { $total_deployed_sidebar = Asset::Deployed()->count(); view()->share('total_deployed_sidebar', $total_deployed_sidebar); @@ -75,13 +86,6 @@ class AssetCountForSidebar \Log::debug($e); } - try { - $settings = Setting::getSettings(); - view()->share('settings', $settings); - } catch (\Exception $e) { - \Log::debug($e); - } - try { $total_due_for_audit = Asset::DueForAudit($settings)->count(); view()->share('total_due_for_audit', $total_due_for_audit); diff --git a/app/Http/Transformers/UsersTransformer.php b/app/Http/Transformers/UsersTransformer.php index 0ebaca2692..64752d0445 100644 --- a/app/Http/Transformers/UsersTransformer.php +++ b/app/Http/Transformers/UsersTransformer.php @@ -21,6 +21,7 @@ class UsersTransformer public function transformUser(User $user) { + $array = [ 'id' => (int) $user->id, 'avatar' => e($user->present()->gravatar), @@ -64,6 +65,8 @@ class UsersTransformer 'licenses_count' => (int) $user->licenses_count, 'accessories_count' => (int) $user->accessories_count, 'consumables_count' => (int) $user->consumables_count, + 'manages_users_count' => (int) $user->manages_users_count, + 'manages_locations_count' => (int) $user->manages_locations_count, 'company' => ($user->company) ? ['id' => (int) $user->company->id, 'name'=> e($user->company->name)] : null, 'created_by' => ($user->createdBy) ? [ 'id' => (int) $user->createdBy->id, diff --git a/app/Models/User.php b/app/Models/User.php index e535fa0fde..e30136703e 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -214,10 +214,12 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo public function isDeletable() { return Gate::allows('delete', $this) - && ($this->assets()->count() === 0) - && ($this->licenses()->count() === 0) - && ($this->consumables()->count() === 0) - && ($this->accessories()->count() === 0) + && ($this->assets->count() === 0) + && ($this->licenses->count() === 0) + && ($this->consumables->count() === 0) + && ($this->accessories->count() === 0) + && ($this->managedLocations->count() === 0) + && ($this->managesUsers->count() === 0) && ($this->deleted_at == ''); } @@ -410,6 +412,19 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo return $this->belongsTo(self::class, 'manager_id')->withTrashed(); } + /** + * Establishes the user -> managed users relationship + * + * @author A. Gianotto + * @since [v6.4.1] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function managesUsers() + { + return $this->hasMany(\App\Models\User::class, 'manager_id'); + } + + /** * Establishes the user -> managed locations relationship * diff --git a/app/Presenters/UserPresenter.php b/app/Presenters/UserPresenter.php index 4726205c72..a5b99adb14 100644 --- a/app/Presenters/UserPresenter.php +++ b/app/Presenters/UserPresenter.php @@ -221,7 +221,7 @@ class UserPresenter extends Presenter 'switchable' => true, 'escape' => true, 'class' => 'css-barcode', - 'title' => 'Assets', + 'title' => trans('general.assets'), 'visible' => true, ], [ @@ -230,7 +230,7 @@ class UserPresenter extends Presenter 'sortable' => true, 'switchable' => true, 'class' => 'css-license', - 'title' => 'License', + 'title' => trans('general.licenses'), 'visible' => true, ], [ @@ -239,7 +239,7 @@ class UserPresenter extends Presenter 'sortable' => true, 'switchable' => true, 'class' => 'css-consumable', - 'title' => 'Consumables', + 'title' => trans('general.consumables'), 'visible' => true, ], [ @@ -248,7 +248,25 @@ class UserPresenter extends Presenter 'sortable' => true, 'switchable' => true, 'class' => 'css-accessory', - 'title' => 'Accessories', + 'title' => trans('general.accessories'), + 'visible' => true, + ], + [ + 'field' => 'manages_users_count', + 'searchable' => false, + 'sortable' => true, + 'switchable' => true, + 'class' => 'css-users', + 'title' => trans('admin/users/table.managed_users'), + 'visible' => true, + ], + [ + 'field' => 'manages_locations_count', + 'searchable' => false, + 'sortable' => true, + 'switchable' => true, + 'class' => 'css-location', + 'title' => trans('admin/users/table.managed_locations'), 'visible' => true, ], [ diff --git a/public/css/build/app.css b/public/css/build/app.css index 9096f553e1..fc299c1967 100644 Binary files a/public/css/build/app.css and b/public/css/build/app.css differ diff --git a/public/css/build/overrides.css b/public/css/build/overrides.css index 86cabbe245..3af6b4e09e 100644 Binary files a/public/css/build/overrides.css and b/public/css/build/overrides.css differ diff --git a/public/css/dist/all.css b/public/css/dist/all.css index d1dd88303e..eb5759c82c 100644 Binary files a/public/css/dist/all.css and b/public/css/dist/all.css differ diff --git a/public/mix-manifest.json b/public/mix-manifest.json index c2b1fc30dc..8fd460c493 100644 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -1,8 +1,8 @@ { "/js/build/app.js": "/js/build/app.js?id=6bbc4dd6b643fefe492261fdfe6fae5a", "/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=392cc93cfc0be0349bab9697669dd091", - "/css/build/overrides.css": "/css/build/overrides.css?id=496c37399034d10dcc70be93f0a652ee", - "/css/build/app.css": "/css/build/app.css?id=6fe97f315d9bddfbcb4b00e4fb5ad91e", + "/css/build/overrides.css": "/css/build/overrides.css?id=c071d0741611371e84c380de2fb13b46", + "/css/build/app.css": "/css/build/app.css?id=cd07d2f45297c702527a330dce45dd46", "/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=f25c77ed07053646a42e9c19923d24fa", "/css/dist/skins/skin-orange.css": "/css/dist/skins/skin-orange.css?id=268041e902b019730c23ee3875838005", "/css/dist/skins/skin-orange-dark.css": "/css/dist/skins/skin-orange-dark.css?id=03075904b967308132b810bc0205ab1c", @@ -18,7 +18,7 @@ "/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=b48f4d8af0e1ca5621c161e93951109f", "/css/dist/skins/skin-contrast.css": "/css/dist/skins/skin-contrast.css?id=f0fbbb0ac729ea092578fb05ca615460", "/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=b9a74ec0cd68f83e7480d5ae39919beb", - "/css/dist/all.css": "/css/dist/all.css?id=b9fabcaa30b6364ecc464012fc124cb0", + "/css/dist/all.css": "/css/dist/all.css?id=3785387b68b5d74dccd037fe5340e038", "/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced1cf5f13147f7", "/css/dist/signature-pad.min.css": "/css/dist/signature-pad.min.css?id=6a89d3cd901305e66ced1cf5f13147f7", "/css/webfonts/fa-brands-400.ttf": "/css/webfonts/fa-brands-400.ttf?id=0141634c24336be626e05c8b77d1fa27", diff --git a/resources/assets/less/overrides.less b/resources/assets/less/overrides.less index 31e85ca26e..12bce00bb6 100644 --- a/resources/assets/less/overrides.less +++ b/resources/assets/less/overrides.less @@ -586,6 +586,8 @@ th.css-barcode > .th-inner, th.css-license > .th-inner, th.css-consumable > .th-inner, th.css-envelope > .th-inner, +th.css-users > .th-inner, +th.css-location > .th-inner, th.css-accessory > .th-inner { font-size: 0px; @@ -602,6 +604,8 @@ th.css-barcode > .th-inner::before, th.css-license > .th-inner::before, th.css-consumable > .th-inner::before, th.css-envelope > .th-inner::before, +th.css-users > .th-inner::before, +th.css-location > .th-inner::before, th.css-accessory > .th-inner::before { @@ -621,6 +625,7 @@ th.css-padlock > .th-inner::before } /** +BEGIN ICON TABLE HEADERS Set the font-weight css property as 900 (For Solid), 400 (Regular or Brands), 300 (Light for pro icons). **/ th.css-barcode > .th-inner::before @@ -643,12 +648,20 @@ th.css-envelope > .th-inner::before content: "\f0e0"; font-family: "Font Awesome 5 Free"; font-weight: 400; } - th.css-accessory > .th-inner::before { content: "\f11c"; font-family: "Font Awesome 5 Free"; font-weight: 400; } +th.css-users > .th-inner::before { + content: "\f0c0"; font-family: "Font Awesome 5 Free"; font-size: 15px; +} + +th.css-location > .th-inner::before { + content: "\f3c5"; font-family: "Font Awesome 5 Free"; font-size: 19px; margin-bottom: 0px; +} + + .small-box .inner { padding-left: 15px; padding-right: 15px; diff --git a/resources/lang/en-US/admin/users/table.php b/resources/lang/en-US/admin/users/table.php index b8b919bf28..7c5fb2cad5 100644 --- a/resources/lang/en-US/admin/users/table.php +++ b/resources/lang/en-US/admin/users/table.php @@ -20,6 +20,7 @@ return array( 'lock_passwords' => 'Login details cannot be changed on this installation.', 'manager' => 'Manager', 'managed_locations' => 'Managed Locations', + 'managed_users' => 'Managed Users', 'name' => 'Name', 'nogroup' => 'No groups have been created yet. To add one, visit: ', 'notes' => 'Notes', diff --git a/resources/views/users/view.blade.php b/resources/views/users/view.blade.php index 3dbd9ff531..f79270d18c 100755 --- a/resources/views/users/view.blade.php +++ b/resources/views/users/view.blade.php @@ -89,9 +89,9 @@ - @if ($user->managedLocations()->count() >= 0 ) + @if ($user->managedLocations->count() >= 0 )
  • - +
  • @endif - @can('update', $user) + @if ($user->managesUsers->count() >= 0 ) +
  • + + + +
  • + @endif + + + @can('update', $user)