Skip to content

Commit

Permalink
Merge pull request #14697 from snipe/bug/sc-25502/disable_delete_if_n…
Browse files Browse the repository at this point in the history
…ot_deletable_user

Fixed UI where delete button was not disabled even if the user couldn't be deleted
  • Loading branch information
snipe committed May 8, 2024
2 parents 86661e7 + 8c327e6 commit 46779ca
Show file tree
Hide file tree
Showing 12 changed files with 247 additions and 35 deletions.
33 changes: 20 additions & 13 deletions app/Http/Controllers/Api/UsersController.php
Expand Up @@ -75,8 +75,8 @@ public function index(Request $request)
'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')) {
Expand Down Expand Up @@ -187,6 +187,14 @@ public function index(Request $request)
$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'));
}
Expand Down Expand Up @@ -244,6 +252,8 @@ public function index(Request $request)
'licenses_count',
'consumables_count',
'accessories_count',
'manages_user_count',
'manages_locations_count',
'phone',
'address',
'city',
Expand Down Expand Up @@ -405,11 +415,15 @@ public function show($id)
{
$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);
}


Expand Down Expand Up @@ -470,7 +484,6 @@ public function update(SaveUserRequest $request, $id)
}



// 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)]);
Expand All @@ -480,12 +493,6 @@ public function update(SaveUserRequest $request, $id)

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')) {

Expand Down
3 changes: 3 additions & 0 deletions app/Http/Transformers/UsersTransformer.php
Expand Up @@ -21,6 +21,7 @@ public function transformUsers(Collection $users, $total)

public function transformUser(User $user)
{

$array = [
'id' => (int) $user->id,
'avatar' => e($user->present()->gravatar),
Expand Down Expand Up @@ -64,6 +65,8 @@ public function transformUser(User $user)
'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,
Expand Down
23 changes: 19 additions & 4 deletions app/Models/User.php
Expand Up @@ -214,10 +214,12 @@ public function isSuperUser()
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 == '');
}

Expand Down Expand Up @@ -410,6 +412,19 @@ public function manager()
return $this->belongsTo(self::class, 'manager_id')->withTrashed();
}

/**
* Establishes the user -> managed users relationship
*
* @author A. Gianotto <snipe@snipe.net>
* @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
*
Expand Down
26 changes: 22 additions & 4 deletions app/Presenters/UserPresenter.php
Expand Up @@ -221,7 +221,7 @@ public static function dataTableLayout()
'switchable' => true,
'escape' => true,
'class' => 'css-barcode',
'title' => 'Assets',
'title' => trans('general.assets'),
'visible' => true,
],
[
Expand All @@ -230,7 +230,7 @@ public static function dataTableLayout()
'sortable' => true,
'switchable' => true,
'class' => 'css-license',
'title' => 'License',
'title' => trans('general.licenses'),
'visible' => true,
],
[
Expand All @@ -239,7 +239,7 @@ public static function dataTableLayout()
'sortable' => true,
'switchable' => true,
'class' => 'css-consumable',
'title' => 'Consumables',
'title' => trans('general.consumables'),
'visible' => true,
],
[
Expand All @@ -248,7 +248,25 @@ public static function dataTableLayout()
'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,
],
[
Expand Down
16 changes: 16 additions & 0 deletions public/css/build/app.css
Expand Up @@ -881,6 +881,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;
line-height: 0.75 !important;
Expand All @@ -894,6 +896,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 {
display: inline-block;
font-size: 20px;
Expand All @@ -908,6 +912,7 @@ th.css-padlock > .th-inner::before {
font-size: 12px;
}
/**
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 {
Expand Down Expand Up @@ -935,6 +940,17 @@ th.css-accessory > .th-inner::before {
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;
Expand Down
16 changes: 16 additions & 0 deletions public/css/build/overrides.css
Expand Up @@ -514,6 +514,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;
line-height: 0.75 !important;
Expand All @@ -527,6 +529,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 {
display: inline-block;
font-size: 20px;
Expand All @@ -541,6 +545,7 @@ th.css-padlock > .th-inner::before {
font-size: 12px;
}
/**
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 {
Expand Down Expand Up @@ -568,6 +573,17 @@ th.css-accessory > .th-inner::before {
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;
Expand Down
32 changes: 32 additions & 0 deletions public/css/dist/all.css
Expand Up @@ -22408,6 +22408,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;
line-height: 0.75 !important;
Expand All @@ -22421,6 +22423,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 {
display: inline-block;
font-size: 20px;
Expand All @@ -22435,6 +22439,7 @@ th.css-padlock > .th-inner::before {
font-size: 12px;
}
/**
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 {
Expand Down Expand Up @@ -22462,6 +22467,17 @@ th.css-accessory > .th-inner::before {
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;
Expand Down Expand Up @@ -23686,6 +23702,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;
line-height: 0.75 !important;
Expand All @@ -23699,6 +23717,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 {
display: inline-block;
font-size: 20px;
Expand All @@ -23713,6 +23733,7 @@ th.css-padlock > .th-inner::before {
font-size: 12px;
}
/**
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 {
Expand Down Expand Up @@ -23740,6 +23761,17 @@ th.css-accessory > .th-inner::before {
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;
Expand Down
6 changes: 3 additions & 3 deletions public/mix-manifest.json
@@ -1,8 +1,8 @@
{
"/js/build/app.js": "/js/build/app.js?id=ea5f3edebafdb29b616d23fa89106080",
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=f677207c6cf9678eb539abecb408c374",
"/css/build/overrides.css": "/css/build/overrides.css?id=be3c0a217bc6c0e0744f75faed784887",
"/css/build/app.css": "/css/build/app.css?id=a168b0a799aa800ee926bffa1b1a434a",
"/css/build/overrides.css": "/css/build/overrides.css?id=3d1aa807fc9395794b76f4cdab99c984",
"/css/build/app.css": "/css/build/app.css?id=40e80d931c21cde71b27be4c8eaaea62",
"/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=dc383f8560a8d4adb51d44fb4043e03b",
"/css/dist/skins/skin-orange.css": "/css/dist/skins/skin-orange.css?id=6f0563e726c2fe4fab4026daaa5bfdf2",
"/css/dist/skins/skin-orange-dark.css": "/css/dist/skins/skin-orange-dark.css?id=620b684d9dd9d3bb5fdda00a3a2467c3",
Expand All @@ -18,7 +18,7 @@
"/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=0a82a6ae6bb4e58fe62d162c4fb50397",
"/css/dist/skins/skin-contrast.css": "/css/dist/skins/skin-contrast.css?id=da6c7997d9de2f8329142399f0ce50da",
"/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=44bf834f2110504a793dadec132a5898",
"/css/dist/all.css": "/css/dist/all.css?id=6e9aa08b535262053b95aee495caa7df",
"/css/dist/all.css": "/css/dist/all.css?id=b51ba67a606c04c8f12fa30adcf33fd0",
"/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",
Expand Down

0 comments on commit 46779ca

Please sign in to comment.