fix: 🐛 Sorting on admin/users datatable
This commit is contained in:
parent
b25ce96efb
commit
a0268f1c47
|
@ -7,6 +7,7 @@ use App\Events\UserUpdateCreditsEvent;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Notifications\DynamicNotification;
|
use App\Notifications\DynamicNotification;
|
||||||
|
use App\Traits\DatatablesSortable;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Illuminate\Contracts\Foundation\Application;
|
use Illuminate\Contracts\Foundation\Application;
|
||||||
use Illuminate\Contracts\View\Factory;
|
use Illuminate\Contracts\View\Factory;
|
||||||
|
@ -26,6 +27,8 @@ use Spatie\QueryBuilder\QueryBuilder;
|
||||||
|
|
||||||
class UserController extends Controller
|
class UserController extends Controller
|
||||||
{
|
{
|
||||||
|
use DatatablesSortable;
|
||||||
|
|
||||||
private Pterodactyl $pterodactyl;
|
private Pterodactyl $pterodactyl;
|
||||||
|
|
||||||
public function __construct(Pterodactyl $pterodactyl)
|
public function __construct(Pterodactyl $pterodactyl)
|
||||||
|
@ -132,7 +135,7 @@ class UserController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! is_null($request->input('new_password'))) {
|
if (!is_null($request->input('new_password'))) {
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'new_password' => 'required|string|min:8',
|
'new_password' => 'required|string|min:8',
|
||||||
'new_password_confirmation' => 'required|same:new_password',
|
'new_password_confirmation' => 'required|same:new_password',
|
||||||
|
@ -259,7 +262,7 @@ class UserController extends Controller
|
||||||
public function toggleSuspended(User $user)
|
public function toggleSuspended(User $user)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
! $user->isSuspended() ? $user->suspend() : $user->unSuspend();
|
!$user->isSuspended() ? $user->suspend() : $user->unSuspend();
|
||||||
} catch (Exception $exception) {
|
} catch (Exception $exception) {
|
||||||
return redirect()->back()->with('error', $exception->getMessage());
|
return redirect()->back()->with('error', $exception->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -270,32 +273,42 @@ class UserController extends Controller
|
||||||
/**
|
/**
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function dataTable()
|
public function dataTable(Request $request)
|
||||||
{
|
{
|
||||||
$query = User::with(['discordUser', 'servers'])->select('users.*');
|
$query = User::withCount(['servers'])->with('discordUser');
|
||||||
|
// manually count referrals in user_referrals table
|
||||||
|
$query->addSelect(DB::raw('(SELECT COUNT(*) FROM user_referrals WHERE user_referrals.referral_id = users.id) as referrals_count'));
|
||||||
|
|
||||||
|
|
||||||
|
if ($request->has('order')) {
|
||||||
|
$query = $this->sortByColumn($request->input('order'), $request->input('columns'), $query);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return datatables($query)
|
return datatables($query)
|
||||||
->addColumn('avatar', function (User $user) {
|
->addColumn('avatar', function (User $user) {
|
||||||
return '<img width="28px" height="28px" class="rounded-circle ml-1" src="'.$user->getAvatar().'">';
|
return '<img width="28px" height="28px" class="rounded-circle ml-1" src="' . $user->getAvatar() . '">';
|
||||||
})
|
})
|
||||||
->addColumn('credits', function (User $user) {
|
->addColumn('credits', function (User $user) {
|
||||||
return '<i class="fas fa-coins mr-2"></i> '.$user->credits();
|
return '<i class="fas fa-coins mr-2"></i> ' . $user->credits();
|
||||||
})
|
})
|
||||||
->addColumn('verified', function (User $user) {
|
->addColumn('verified', function (User $user) {
|
||||||
return $user->getVerifiedStatus();
|
return $user->getVerifiedStatus();
|
||||||
})
|
})
|
||||||
->addColumn('servers', function (User $user) {
|
->addColumn('servers_count', function (User $user) {
|
||||||
return $user->servers->count();
|
return $user->servers_count;
|
||||||
})
|
})
|
||||||
->addColumn('referrals', function (User $user) {
|
->addColumn('referrals_count', function (User $user) {
|
||||||
return DB::table('user_referrals')->where('referral_id', '=', $user->id)->count();
|
return $user->referrals_count;
|
||||||
})
|
})
|
||||||
->addColumn('discordId', function (User $user) {
|
->addColumn('discordId', function (User $user) {
|
||||||
return $user->discordUser ? $user->discordUser->id : '';
|
return $user->discordUser ? $user->discordUser->id : '';
|
||||||
})
|
})
|
||||||
->addColumn('last_seen', function (User $user) {
|
->addColumn('last_seen', function (User $user) {
|
||||||
return ['display' => $user->last_seen ? $user->last_seen->diffForHumans() : '',
|
return [
|
||||||
'raw' => $user->last_seen ? strtotime($user->last_seen) : '', ];
|
'display' => $user->last_seen ? $user->last_seen->diffForHumans() : __('Never'),
|
||||||
|
'raw' => $user->last_seen ? strtotime($user->last_seen) : '',
|
||||||
|
];
|
||||||
})
|
})
|
||||||
->addColumn('actions', function (User $user) {
|
->addColumn('actions', function (User $user) {
|
||||||
$suspendColor = $user->isSuspended() ? 'btn-success' : 'btn-warning';
|
$suspendColor = $user->isSuspended() ? 'btn-success' : 'btn-warning';
|
||||||
|
@ -303,19 +316,19 @@ class UserController extends Controller
|
||||||
$suspendText = $user->isSuspended() ? __('Unsuspend') : __('Suspend');
|
$suspendText = $user->isSuspended() ? __('Unsuspend') : __('Suspend');
|
||||||
|
|
||||||
return '
|
return '
|
||||||
<a data-content="'.__('Login as User').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.users.loginas', $user->id).'" class="btn btn-sm btn-primary mr-1"><i class="fas fa-sign-in-alt"></i></a>
|
<a data-content="' . __('Login as User') . '" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.users.loginas', $user->id) . '" class="btn btn-sm btn-primary mr-1"><i class="fas fa-sign-in-alt"></i></a>
|
||||||
<a data-content="'.__('Verify').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.users.verifyEmail', $user->id).'" class="btn btn-sm btn-secondary mr-1"><i class="fas fa-envelope"></i></a>
|
<a data-content="' . __('Verify') . '" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.users.verifyEmail', $user->id) . '" class="btn btn-sm btn-secondary mr-1"><i class="fas fa-envelope"></i></a>
|
||||||
<a data-content="'.__('Show').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.users.show', $user->id).'" class="btn btn-sm text-white btn-warning mr-1"><i class="fas fa-eye"></i></a>
|
<a data-content="' . __('Show') . '" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.users.show', $user->id) . '" class="btn btn-sm text-white btn-warning mr-1"><i class="fas fa-eye"></i></a>
|
||||||
<a data-content="'.__('Edit').'" data-toggle="popover" data-trigger="hover" data-placement="top" href="'.route('admin.users.edit', $user->id).'" class="btn btn-sm btn-info mr-1"><i class="fas fa-pen"></i></a>
|
<a data-content="' . __('Edit') . '" data-toggle="popover" data-trigger="hover" data-placement="top" href="' . route('admin.users.edit', $user->id) . '" class="btn btn-sm btn-info mr-1"><i class="fas fa-pen"></i></a>
|
||||||
<form class="d-inline" method="post" action="'.route('admin.users.togglesuspend', $user->id).'">
|
<form class="d-inline" method="post" action="' . route('admin.users.togglesuspend', $user->id) . '">
|
||||||
'.csrf_field().'
|
' . csrf_field() . '
|
||||||
<button data-content="'.$suspendText.'" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm '.$suspendColor.' text-white mr-1"><i class="far '.$suspendIcon.'"></i></button>
|
<button data-content="' . $suspendText . '" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm ' . $suspendColor . ' text-white mr-1"><i class="far ' . $suspendIcon . '"></i></button>
|
||||||
</form>
|
</form>
|
||||||
<form class="d-inline" onsubmit="return submitResult();" method="post" action="'.route('admin.users.destroy', $user->id).'">
|
<form class="d-inline" onsubmit="return submitResult();" method="post" action="' . route('admin.users.destroy', $user->id) . '">
|
||||||
'.csrf_field().'
|
' . csrf_field() . '
|
||||||
'.method_field('DELETE').'
|
' . method_field('DELETE') . '
|
||||||
<button data-content="'.__('Delete').'" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm btn-danger mr-1"><i class="fas fa-trash"></i></button>
|
<button data-content="' . __('Delete') . '" data-toggle="popover" data-trigger="hover" data-placement="top" class="btn btn-sm btn-danger mr-1"><i class="fas fa-trash"></i></button>
|
||||||
</form>
|
</form>
|
||||||
';
|
';
|
||||||
})
|
})
|
||||||
->editColumn('role', function (User $user) {
|
->editColumn('role', function (User $user) {
|
||||||
|
@ -334,14 +347,14 @@ class UserController extends Controller
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return '<span class="badge '.$badgeColor.'">'.$user->role.'</span>';
|
return '<span class="badge ' . $badgeColor . '">' . $user->role . '</span>';
|
||||||
})
|
})
|
||||||
->editColumn('name', function (User $user) {
|
->editColumn('name', function (User $user) {
|
||||||
return '<a class="text-info" target="_blank" href="'.config('SETTINGS::SYSTEM:PTERODACTYL:URL').'/admin/users/view/'.$user->pterodactyl_id.'">'.strip_tags($user->name).'</a>';
|
return '<a class="text-info" target="_blank" href="' . config('SETTINGS::SYSTEM:PTERODACTYL:URL') . '/admin/users/view/' . $user->pterodactyl_id . '">' . strip_tags($user->name) . '</a>';
|
||||||
})
|
})
|
||||||
/*->orderColumn('last_seen', function ($query) {
|
->orderColumn('last_seen', function ($query) {
|
||||||
$query->orderBy('last_seen', "desc");
|
$query->orderBy('last_seen', "desc");
|
||||||
})*/
|
})
|
||||||
->rawColumns(['avatar', 'name', 'credits', 'role', 'usage', 'referrals', 'actions', 'last_seen'])
|
->rawColumns(['avatar', 'name', 'credits', 'role', 'usage', 'referrals', 'actions', 'last_seen'])
|
||||||
->make(true);
|
->make(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,13 @@
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<h1>{{__('Users')}}</h1>
|
<h1>{{ __('Users') }}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<ol class="breadcrumb float-sm-right">
|
<ol class="breadcrumb float-sm-right">
|
||||||
<li class="breadcrumb-item"><a href="{{route('home')}}">{{__('Dashboard')}}</a></li>
|
<li class="breadcrumb-item"><a href="{{ route('home') }}">{{ __('Dashboard') }}</a></li>
|
||||||
<li class="breadcrumb-item"><a class="text-muted" href="{{route('admin.users.index')}}">{{__('Users')}}</a></li>
|
<li class="breadcrumb-item"><a class="text-muted"
|
||||||
|
href="{{ route('admin.users.index') }}">{{ __('Users') }}</a></li>
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -27,9 +28,9 @@
|
||||||
|
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
<h5 class="card-title"><i class="fas fa-users mr-2"></i>{{__('Users')}}</h5>
|
<h5 class="card-title"><i class="fas fa-users mr-2"></i>{{ __('Users') }}</h5>
|
||||||
<a href="{{route('admin.users.notifications')}}" class="btn btn-sm btn-primary"><i
|
<a href="{{ route('admin.users.notifications') }}" class="btn btn-sm btn-primary"><i
|
||||||
class="fas fa-paper-plane mr-1"></i>{{__('Notify')}}</a>
|
class="fas fa-paper-plane mr-1"></i>{{ __('Notify') }}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -37,21 +38,21 @@
|
||||||
|
|
||||||
<table id="datatable" class="table table-striped">
|
<table id="datatable" class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>discordId</th>
|
<th>discordId</th>
|
||||||
<th>ip</th>
|
<th>ip</th>
|
||||||
<th>pterodactyl_id</th>
|
<th>pterodactyl_id</th>
|
||||||
<th>{{__('Avatar')}}</th>
|
<th>{{ __('Avatar') }}</th>
|
||||||
<th>{{__('Name')}}</th>
|
<th>{{ __('Name') }}</th>
|
||||||
<th>{{__('Role')}}</th>
|
<th>{{ __('Role') }}</th>
|
||||||
<th>{{__('Email')}}</th>
|
<th>{{ __('Email') }}</th>
|
||||||
<th>{{CREDITS_DISPLAY_NAME}}</th>
|
<th>{{ CREDITS_DISPLAY_NAME }}</th>
|
||||||
<th>{{__('Servers')}}</th>
|
<th>{{ __('Servers') }}</th>
|
||||||
<th>{{__("Referrals")}}</th>
|
<th>{{ __('Referrals') }}</th>
|
||||||
<th>{{__('Verified')}}</th>
|
<th>{{ __('Verified') }}</th>
|
||||||
<th>{{__('Last seen')}}</th>
|
<th>{{ __('Last seen') }}</th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -68,41 +69,78 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function submitResult() {
|
function submitResult() {
|
||||||
return confirm("{{__('Are you sure you wish to delete?')}}") !== false;
|
return confirm("{{ __('Are you sure you wish to delete?') }}") !== false;
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
$('#datatable').DataTable({
|
$('#datatable').DataTable({
|
||||||
language: {
|
language: {
|
||||||
url: '//cdn.datatables.net/plug-ins/1.11.3/i18n/{{config("SETTINGS::LOCALE:DATATABLES")}}.json'
|
url: '//cdn.datatables.net/plug-ins/1.11.3/i18n/{{ config('SETTINGS::LOCALE:DATATABLES') }}.json'
|
||||||
},
|
},
|
||||||
processing: true,
|
processing: true,
|
||||||
serverSide: true, //why was this set to false before? increased loadingtimes by 10 seconds
|
serverSide: true, //why was this set to false before? increased loadingtimes by 10 seconds
|
||||||
stateSave: true,
|
stateSave: true,
|
||||||
ajax: "{{route('admin.users.datatable')}}",
|
ajax: "{{ route('admin.users.datatable') }}",
|
||||||
order: [[ 11, "asc" ]],
|
|
||||||
columns: [
|
columns: [{
|
||||||
{data: 'discordId', visible: false, name: 'discordUser.id'},
|
data: 'discordId',
|
||||||
{data: 'pterodactyl_id', visible: false},
|
visible: false,
|
||||||
{data: 'ip', visible: false},
|
name: 'discordUser.id'
|
||||||
{data: 'avatar' , sortable : false},
|
},
|
||||||
{data: 'name'},
|
{
|
||||||
{data: 'role'},
|
data: 'pterodactyl_id',
|
||||||
{data: 'email', name: 'users.email'},
|
visible: false
|
||||||
{data: 'credits' , name : 'users.credits'},
|
},
|
||||||
{data: 'servers'},
|
{
|
||||||
{data: 'referrals'},
|
data: 'ip',
|
||||||
{data: 'verified' , sortable : false},
|
visible: false
|
||||||
{data: 'last_seen', type: 'num', render: {_: 'display', sort: 'raw'}},
|
},
|
||||||
{data: 'actions' , sortable : false},
|
{
|
||||||
|
data: 'avatar',
|
||||||
|
sortable: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'name'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'role'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'email',
|
||||||
|
name: 'users.email'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'credits',
|
||||||
|
name: 'users.credits'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'servers_count'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'referrals_count',
|
||||||
|
sortable: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'verified',
|
||||||
|
sortable: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'last_seen',
|
||||||
|
type: 'num',
|
||||||
|
render: {
|
||||||
|
_: 'display',
|
||||||
|
sort: 'raw'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
data: 'actions',
|
||||||
|
sortable: false
|
||||||
|
},
|
||||||
],
|
],
|
||||||
fnDrawCallback: function( oSettings ) {
|
fnDrawCallback: function(oSettings) {
|
||||||
$('[data-toggle="popover"]').popover();
|
$('[data-toggle="popover"]').popover();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@endsection
|
@endsection
|
||||||
|
|
Loading…
Reference in a new issue