Compare commits
3 Commits
master
...
more-fixes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8b60b1d17 | ||
|
|
7dbd8e99ba | ||
|
|
b5a8b29af5 |
@@ -336,6 +336,11 @@ class UsersController extends Controller
|
|||||||
]
|
]
|
||||||
)->where('show_in_list', '=', '1');
|
)->where('show_in_list', '=', '1');
|
||||||
|
|
||||||
|
if (($request->filled('subordinates')) && (!auth()->user()->isSuperUser())) {
|
||||||
|
// Regular manager sees only their subordinates + self
|
||||||
|
$users = auth()->user()->allSubordinates();
|
||||||
|
}
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
if ($request->filled('search')) {
|
||||||
$users = $users->where(function ($query) use ($request) {
|
$users = $users->where(function ($query) use ($request) {
|
||||||
$query->SimpleNameSearch($request->get('search'))
|
$query->SimpleNameSearch($request->get('search'))
|
||||||
|
|||||||
@@ -47,62 +47,6 @@ class ViewAssetsController extends Controller
|
|||||||
return array_unique($fieldArray);
|
return array_unique($fieldArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get list of users viewable by the current user.
|
|
||||||
*
|
|
||||||
* @param User $authUser
|
|
||||||
* @return \Illuminate\Support\Collection
|
|
||||||
*/
|
|
||||||
private function getViewableUsers(User $authUser): \Illuminate\Support\Collection
|
|
||||||
{
|
|
||||||
// SuperAdmin sees all users
|
|
||||||
if ($authUser->isSuperUser()) {
|
|
||||||
return User::select('id', 'first_name', 'last_name', 'username')
|
|
||||||
->where('activated', 1)
|
|
||||||
->orderBy('last_name')
|
|
||||||
->orderBy('first_name')
|
|
||||||
->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regular manager sees only their subordinates + self
|
|
||||||
$managedUsers = $authUser->getAllSubordinates();
|
|
||||||
|
|
||||||
// If user has subordinates, show them with self at beginning
|
|
||||||
if ($managedUsers->count() > 0) {
|
|
||||||
return collect([$authUser])->merge($managedUsers)
|
|
||||||
->sortBy('last_name')
|
|
||||||
->sortBy('first_name');
|
|
||||||
}
|
|
||||||
|
|
||||||
// User has no subordinates, only sees themselves
|
|
||||||
return collect([$authUser]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the selected user ID from request or default to current user.
|
|
||||||
*
|
|
||||||
* @param Request $request
|
|
||||||
* @param \Illuminate\Support\Collection $subordinates
|
|
||||||
* @param int $defaultUserId
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
private function getSelectedUserId(Request $request, \Illuminate\Support\Collection $subordinates, int $defaultUserId): int
|
|
||||||
{
|
|
||||||
// If no subordinates or no user_id in request, return default
|
|
||||||
if ($subordinates->count() <= 1 || !$request->filled('user_id')) {
|
|
||||||
return $defaultUserId;
|
|
||||||
}
|
|
||||||
|
|
||||||
$requestedUserId = (int) $request->input('user_id');
|
|
||||||
|
|
||||||
// Validate if the requested user is allowed
|
|
||||||
if ($subordinates->contains('id', $requestedUserId)) {
|
|
||||||
return $requestedUserId;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If invalid ID or not authorized, return default
|
|
||||||
return $defaultUserId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show user's assigned assets with optional manager view functionality.
|
* Show user's assigned assets with optional manager view functionality.
|
||||||
@@ -110,18 +54,29 @@ class ViewAssetsController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function getIndex(Request $request) : View | RedirectResponse
|
public function getIndex(Request $request) : View | RedirectResponse
|
||||||
{
|
{
|
||||||
$authUser = auth()->user();
|
|
||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
$subordinates = collect();
|
$subordinate_count = 0;
|
||||||
$selectedUserId = $authUser->id;
|
$viewingUser = auth()->user();
|
||||||
|
$userToView = auth()->user();
|
||||||
|
$userToViewId = auth()->id();
|
||||||
|
|
||||||
// Process manager view if enabled
|
// Only do the (heavy) recursive subordinate count if the manager view is enabled AND
|
||||||
if ($settings->manager_view_enabled) {
|
// the user is trying to view a different user than themselves.
|
||||||
$subordinates = $this->getViewableUsers($authUser);
|
if (($settings->manager_view_enabled == 1) || (request()->get('user_id') != auth()->id())) {
|
||||||
$selectedUserId = $this->getSelectedUserId($request, $subordinates, $authUser->id);
|
$subordinate_count = auth()->user()->allSubordinates()->count();
|
||||||
|
if (auth()->user()->allSubordinates()->find($userToViewId)) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the data for the user to be viewed (either auth user or selected subordinate)
|
|
||||||
|
\Log::error('Sub count: '.$subordinate_count);
|
||||||
|
\Log::error('$viewingUser '.$viewingUser);
|
||||||
|
\Log::error('$userToView '.$userToView);
|
||||||
|
\Log::error('$userToViewId '.$userToViewId);
|
||||||
|
\Log::error(print_r(auth()->user()->allSubordinates()->get(), true));
|
||||||
|
|
||||||
|
|
||||||
$userToView = User::with([
|
$userToView = User::with([
|
||||||
'assets',
|
'assets',
|
||||||
'assets.model',
|
'assets.model',
|
||||||
@@ -129,23 +84,21 @@ class ViewAssetsController extends Controller
|
|||||||
'consumables',
|
'consumables',
|
||||||
'accessories',
|
'accessories',
|
||||||
'licenses'
|
'licenses'
|
||||||
])->find($selectedUserId);
|
])->find($userToViewId);
|
||||||
|
|
||||||
|
|
||||||
// If the user to view couldn't be found (shouldn't happen with proper logic), redirect with error
|
|
||||||
if (!$userToView) {
|
|
||||||
return redirect()->route('view-assets')->with('error', trans('admin/users/message.user_not_found'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process custom fields for the user being viewed
|
// Process custom fields for the user being viewed
|
||||||
$fieldArray = $this->extractCustomFields($userToView);
|
$fieldArray = $this->extractCustomFields($userToView);
|
||||||
|
|
||||||
|
|
||||||
// Pass the necessary data to the view
|
// Pass the necessary data to the view
|
||||||
return view('account/view-assets', [
|
return view('account/view-assets', [
|
||||||
'user' => $userToView, // Use 'user' for compatibility with the existing view
|
'user' => $userToView, // Use 'user' for compatibility with the existing view
|
||||||
'field_array' => $fieldArray,
|
'field_array' => $fieldArray,
|
||||||
'settings' => $settings,
|
'settings' => $settings,
|
||||||
'subordinates' => $subordinates,
|
'subordinates' => $subordinate_count > 0 ?? false,
|
||||||
'selectedUserId' => $selectedUserId
|
'selectedUserId' => $userToViewId
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -971,10 +971,6 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
|||||||
->orWhere('users.employee_num', 'LIKE', '%' . $search . '%')
|
->orWhere('users.employee_num', 'LIKE', '%' . $search . '%')
|
||||||
->orWhere('users.username', 'LIKE', '%' . $search . '%')
|
->orWhere('users.username', 'LIKE', '%' . $search . '%')
|
||||||
->orwhereRaw('CONCAT(users.first_name," ",users.last_name) LIKE \''.$search.'%\'');
|
->orwhereRaw('CONCAT(users.first_name," ",users.last_name) LIKE \''.$search.'%\'');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1022,6 +1018,22 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function directReports()
|
||||||
|
{
|
||||||
|
return $this->hasMany(User::class, 'manager_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function allSubordinates()
|
||||||
|
{
|
||||||
|
return $this->directReports()->with('allSubordinates');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the current user is a direct or indirect manager of the given user.
|
* Check if the current user is a direct or indirect manager of the given user.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -32369,7 +32369,8 @@ $(function () {
|
|||||||
search: params.term,
|
search: params.term,
|
||||||
page: params.page || 1,
|
page: params.page || 1,
|
||||||
assetStatusType: link.data("asset-status-type"),
|
assetStatusType: link.data("asset-status-type"),
|
||||||
companyId: link.data("company-id")
|
companyId: link.data("company-id"),
|
||||||
|
subordinates: link.data("subordinates")
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
|||||||
3
public/js/dist/all.js
vendored
3
public/js/dist/all.js
vendored
@@ -91302,7 +91302,8 @@ $(function () {
|
|||||||
search: params.term,
|
search: params.term,
|
||||||
page: params.page || 1,
|
page: params.page || 1,
|
||||||
assetStatusType: link.data("asset-status-type"),
|
assetStatusType: link.data("asset-status-type"),
|
||||||
companyId: link.data("company-id")
|
companyId: link.data("company-id"),
|
||||||
|
subordinates: link.data("subordinates")
|
||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"/js/build/app.js": "/js/build/app.js?id=19253af36b58ed3fb6770c7bb944f079",
|
"/js/build/app.js": "/js/build/app.js?id=eeff00aa3bf3497d4ba36c3fd7ca0c20",
|
||||||
"/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=78bfb1c7b5782df4fb0ac7e36f80f847",
|
"/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=78bfb1c7b5782df4fb0ac7e36f80f847",
|
||||||
"/css/dist/skins/_all-skins.css": "/css/dist/skins/_all-skins.css?id=503d0b09e157a22f555e3670d1ec9bb5",
|
"/css/dist/skins/_all-skins.css": "/css/dist/skins/_all-skins.css?id=503d0b09e157a22f555e3670d1ec9bb5",
|
||||||
"/css/build/overrides.css": "/css/build/overrides.css?id=2bfc7b71d951c5ac026dbc034f7373b1",
|
"/css/build/overrides.css": "/css/build/overrides.css?id=2bfc7b71d951c5ac026dbc034f7373b1",
|
||||||
@@ -111,5 +111,5 @@
|
|||||||
"/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=54d676a6ea8677dd48f6c4b3041292cf",
|
"/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=54d676a6ea8677dd48f6c4b3041292cf",
|
||||||
"/js/build/vendor.js": "/js/build/vendor.js?id=89dffa552c6e3abe3a2aac6c9c7b466b",
|
"/js/build/vendor.js": "/js/build/vendor.js?id=89dffa552c6e3abe3a2aac6c9c7b466b",
|
||||||
"/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=60097b6b56d80cbc76257d4ecf6f57b4",
|
"/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=60097b6b56d80cbc76257d4ecf6f57b4",
|
||||||
"/js/dist/all.js": "/js/dist/all.js?id=8c6d7286f667eeb62a0a28a09851a6c3"
|
"/js/dist/all.js": "/js/dist/all.js?id=fe4be0933b6c05df1d795f53da658dc7"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -199,7 +199,10 @@ $(function () {
|
|||||||
page: params.page || 1,
|
page: params.page || 1,
|
||||||
assetStatusType: link.data("asset-status-type"),
|
assetStatusType: link.data("asset-status-type"),
|
||||||
companyId: link.data("company-id"),
|
companyId: link.data("company-id"),
|
||||||
|
subordinates: link.data("subordinates"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
/* processResults: function (data, params) {
|
/* processResults: function (data, params) {
|
||||||
|
|||||||
@@ -6,6 +6,25 @@
|
|||||||
@parent
|
@parent
|
||||||
@stop
|
@stop
|
||||||
|
|
||||||
|
@section('header_right')
|
||||||
|
{{-- Manager View Dropdown --}}
|
||||||
|
@if (isset($settings) && ($settings->manager_view_enabled==1) && ($subordinates))
|
||||||
|
|
||||||
|
<form method="GET" action="{{ route('view-assets') }}" class="pull-right" role="form">
|
||||||
|
<div class="form-group" style="margin-bottom: 0;">
|
||||||
|
<label for="user_id" class="control-label" style="margin-right: 10px;">
|
||||||
|
{{ trans('general.select_user') }}:
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<select class="js-data-ajax form-control select2" data-endpoint="users" data-subordinates="true" data-placeholder="{{ trans('general.select_user') }}" name="user_id" style="width: 450px" id="user_id" aria-label="user_id" onchange="this.form.submit()">
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@endif
|
||||||
|
@stop
|
||||||
|
|
||||||
{{-- Account page content --}}
|
{{-- Account page content --}}
|
||||||
@section('content')
|
@section('content')
|
||||||
|
|
||||||
@@ -25,30 +44,7 @@
|
|||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
{{-- Manager View Dropdown --}}
|
|
||||||
@if (isset($settings) && $settings->manager_view_enabled && isset($subordinates) && $subordinates->count() > 1)
|
|
||||||
<div class="row hidden-print" style="margin-bottom: 15px;">
|
|
||||||
<div class="col-md-12">
|
|
||||||
<form method="GET" action="{{ route('view-assets') }}" class="pull-right" role="form">
|
|
||||||
<div class="form-group" style="margin-bottom: 0;">
|
|
||||||
<label for="user_id" class="control-label" style="margin-right: 10px;">
|
|
||||||
{{ trans('general.view_user_assets') }}:
|
|
||||||
</label>
|
|
||||||
<select name="user_id" id="user_id" class="form-control select2" onchange="this.form.submit()" style="width: 250px; display: inline-block;">
|
|
||||||
@foreach ($subordinates as $subordinate)
|
|
||||||
<option value="{{ $subordinate->id }}" {{ (int)$selectedUserId === (int)$subordinate->id ? ' selected' : '' }}>
|
|
||||||
{{ $subordinate->present()->fullName() }}
|
|
||||||
@if ($subordinate->id == auth()->id())
|
|
||||||
({{ trans('general.me') }})
|
|
||||||
@endif
|
|
||||||
</option>
|
|
||||||
@endforeach
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
@@ -133,44 +129,44 @@
|
|||||||
<div class="col-md-3 col-xs-12 col-sm-push-9">
|
<div class="col-md-3 col-xs-12 col-sm-push-9">
|
||||||
|
|
||||||
<div class="col-md-12 text-center">
|
<div class="col-md-12 text-center">
|
||||||
<img src="{{ $user->present()->gravatar() }}" class=" img-thumbnail hidden-print" style="margin-bottom: 20px;" alt="{{ $user->present()->fullName() }}" alt="User avatar">
|
<img src="{{ $user->present()->gravatar() }}" class="img-thumbnail hidden-print" style="margin-bottom: 20px;" alt="{{ $user->present()->fullName() }}" alt="User avatar">
|
||||||
</div>
|
</div>
|
||||||
@can('self.profile')
|
@if ((isset($selectedUserId)) && ($selectedUserId == auth()->id()))
|
||||||
<div class="col-md-12">
|
@can('self.profile')
|
||||||
<a href="{{ route('profile') }}" style="width: 100%;" class="btn btn-sm btn-warning btn-social btn-block hidden-print">
|
<div class="col-md-12">
|
||||||
<x-icon type="edit" />
|
<a href="{{ route('profile') }}" style="width: 100%;" class="btn btn-sm btn-warning btn-social btn-block hidden-print">
|
||||||
{{ trans('general.editprofile') }}
|
<x-icon type="edit" />
|
||||||
</a>
|
{{ trans('general.editprofile') }}
|
||||||
</div>
|
</a>
|
||||||
@endcan
|
</div>
|
||||||
|
@endcan
|
||||||
|
|
||||||
@if ($user->ldap_import!='1')
|
@if ($user->ldap_import!='1')
|
||||||
<div class="col-md-12" style="padding-top: 5px;">
|
<div class="col-md-12" style="padding-top: 5px;">
|
||||||
<a href="{{ route('account.password.index') }}" style="width: 100%;" class="btn btn-sm btn-primary btn-social btn-block hidden-print" target="_blank" rel="noopener">
|
<a href="{{ route('account.password.index') }}" style="width: 100%;" class="btn btn-sm btn-primary btn-social btn-block hidden-print" target="_blank" rel="noopener">
|
||||||
<x-icon type="password" class="fa-fw" />
|
<x-icon type="password" class="fa-fw" />
|
||||||
{{ trans('general.changepassword') }}
|
{{ trans('general.changepassword') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@can('self.api')
|
||||||
|
<div class="col-md-12" style="padding-top: 5px;">
|
||||||
|
<a href="{{ route('user.api') }}" style="width: 100%;" class="btn btn-sm btn-primary btn-social btn-block hidden-print" target="_blank" rel="noopener">
|
||||||
|
<x-icon type="api-key" class="fa-fw" />
|
||||||
|
{{ trans('general.manage_api_keys') }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
@endcan
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@can('self.api')
|
@if ($user->allAssignedCount() > 0)
|
||||||
<div class="col-md-12" style="padding-top: 5px;">
|
|
||||||
<a href="{{ route('user.api') }}" style="width: 100%;" class="btn btn-sm btn-primary btn-social btn-block hidden-print" target="_blank" rel="noopener">
|
|
||||||
<x-icon type="api-key" class="fa-fw" />
|
|
||||||
{{ trans('general.manage_api_keys') }}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
@endcan
|
|
||||||
|
|
||||||
|
|
||||||
<div class="col-md-12" style="padding-top: 5px;">
|
<div class="col-md-12" style="padding-top: 5px;">
|
||||||
<a href="{{ route('profile.print') }}" style="width: 100%;" class="btn btn-sm btn-primary btn-social btn-block hidden-print" target="_blank" rel="noopener">
|
<a href="{{ route('profile.print') }}" style="width: 100%;" class="btn btn-sm btn-primary btn-social btn-block hidden-print" target="_blank" rel="noopener">
|
||||||
<x-icon type="print" class="fa-fw" />
|
<x-icon type="print" class="fa-fw" />
|
||||||
{{ trans('admin/users/general.print_assigned') }}
|
{{ trans('admin/users/general.print_assigned') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="col-md-12" style="padding-top: 5px;">
|
<div class="col-md-12" style="padding-top: 5px;">
|
||||||
@if (!empty($user->email))
|
@if (!empty($user->email))
|
||||||
<form action="{{ route('profile.email_assets') }}" method="POST">
|
<form action="{{ route('profile.email_assets') }}" method="POST">
|
||||||
@@ -187,8 +183,8 @@
|
|||||||
</button>
|
</button>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
<br><br>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- End button column -->
|
<!-- End button column -->
|
||||||
|
|||||||
Reference in New Issue
Block a user