From b6bc1e50e2d4a851e4fb57c11f42776e65708c1d Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Wed, 11 Jun 2025 06:21:38 -0600 Subject: [PATCH] Update Admin Users dashboard --- .../Controllers/Admin/AdminUserController.php | 621 ++++++------ resources/views/admin/users/home.blade.php | 887 ++++++++++++------ 2 files changed, 952 insertions(+), 556 deletions(-) diff --git a/app/Http/Controllers/Admin/AdminUserController.php b/app/Http/Controllers/Admin/AdminUserController.php index 441f5b305..7b84856a3 100644 --- a/app/Http/Controllers/Admin/AdminUserController.php +++ b/app/Http/Controllers/Admin/AdminUserController.php @@ -2,301 +2,342 @@ namespace App\Http\Controllers\Admin; -use Cache, DB; -use Illuminate\Http\Request; +use App\Jobs\DeletePipeline\DeleteAccountPipeline; +use App\Mail\AdminMessage; use App\ModLog; use App\Profile; +use App\Services\AccountService; +use App\Services\ModLogService; use App\User; -use App\Mail\AdminMessage; +use Cache; +use Illuminate\Http\Request; use Illuminate\Support\Facades\Mail; -use App\Services\ModLogService; -use App\Jobs\DeletePipeline\DeleteAccountPipeline; -use App\Services\AccountService; trait AdminUserController { - public function users(Request $request) - { - $search = $request->has('a') && $request->query('a') == 'search' ? $request->query('q') : null; - $col = $request->query('col') ?? 'id'; - $dir = $request->query('dir') ?? 'desc'; - $offset = $request->has('page') ? $request->input('page') : 0; - $pagination = [ - 'prev' => $offset > 0 ? $offset - 1 : null, - 'next' => $offset + 1, - 'query' => $search ? '&a=search&q=' . $search : null - ]; - $users = User::select('id', 'username', 'status', 'profile_id', 'is_admin') - ->orderBy($col, $dir) - ->when($search, function($q, $search) { - return $q->where('username', 'like', "%{$search}%"); - }) - ->when($offset, function($q, $offset) { - return $q->offset(($offset * 10)); - }) - ->limit(10) - ->get() - ->map(function($u) { - $u['account'] = AccountService::get($u->profile_id, true); - return $u; - }); - - return view('admin.users.home', compact('users', 'pagination')); - } - - public function userShow(Request $request, $id) - { - $user = User::findOrFail($id); - $profile = $user->profile; - return view('admin.users.show', compact('user', 'profile')); - } - - public function userEdit(Request $request, $id) - { - $user = User::findOrFail($id); - $profile = $user->profile; - return view('admin.users.edit', compact('user', 'profile')); - } - - public function userEditSubmit(Request $request, $id) - { - $user = User::findOrFail($id); - $profile = $user->profile; - $changed = false; - $fields = []; - - if($request->filled('name') && $request->input('name') != $user->name) { - $fields['name'] = ['old' => $user->name, 'new' => $request->input('name')]; - $user->name = $profile->name = $request->input('name'); - $changed = true; - } - if($request->filled('username') && $request->input('username') != $user->username) { - $fields['username'] = ['old' => $user->username, 'new' => $request->input('username')]; - $user->username = $profile->username = $request->input('username'); - $changed = true; - } - if($request->filled('email') && $request->input('email') != $user->email) { - if(filter_var($request->input('email'), FILTER_VALIDATE_EMAIL) == false) { - abort(500, 'Invalid email address'); - } - $fields['email'] = ['old' => $user->email, 'new' => $request->input('email')]; - $user->email = $request->input('email'); - $changed = true; - } - if($request->input('bio') != $profile->bio) { - $fields['bio'] = ['old' => $user->bio, 'new' => $request->input('bio')]; - $profile->bio = $request->input('bio'); - $changed = true; - } - if($request->input('website') != $profile->website) { - $fields['website'] = ['old' => $user->website, 'new' => $request->input('website')]; - $profile->website = $request->input('website'); - $changed = true; - } - - if($changed == true) { - ModLogService::boot() - ->objectUid($user->id) - ->objectId($user->id) - ->objectType('App\User::class') - ->user($request->user()) - ->action('admin.user.edit') - ->metadata([ - 'fields' => $fields - ]) - ->accessLevel('admin') - ->save(); - $profile->save(); - $user->save(); - } - - - return redirect('/i/admin/users/show/' . $user->id); - } - - public function userActivity(Request $request, $id) - { - $user = User::findOrFail($id); - $profile = $user->profile; - $logs = $user->accountLog()->orderByDesc('created_at')->paginate(10); - return view('admin.users.activity', compact('user', 'profile', 'logs')); - } - - public function userMessage(Request $request, $id) - { - $user = User::findOrFail($id); - $profile = $user->profile; - return view('admin.users.message', compact('user', 'profile')); - } - - public function userMessageSend(Request $request, $id) - { - $this->validate($request, [ - 'message' => 'required|string|min:5|max:500' - ]); - $user = User::findOrFail($id); - $profile = $user->profile; - $message = $request->input('message'); - Mail::to($user->email)->send(new AdminMessage($message)); - ModLogService::boot() - ->objectUid($user->id) - ->objectId($user->id) - ->objectType('App\User::class') - ->user($request->user()) - ->action('admin.user.mail') - ->metadata([ - 'message' => $message - ]) - ->accessLevel('admin') - ->save(); - return redirect('/i/admin/users/show/' . $user->id); - } - - public function userModTools(Request $request, $id) - { - $user = User::findOrFail($id); - $profile = $user->profile; - return view('admin.users.modtools', compact('user', 'profile')); - } - - public function userModLogs(Request $request, $id) - { - $user = User::findOrFail($id); - $profile = $user->profile; - $logs = ModLog::whereObjectUid($user->id) - ->orderByDesc('created_at') - ->simplePaginate(10); - return view('admin.users.modlogs', compact('user', 'profile', 'logs')); - } - - public function userModLogsMessage(Request $request, $id) - { - $this->validate($request, [ - 'message' => 'required|string|min:5|max:500' - ]); - $user = User::findOrFail($id); - $profile = $user->profile; - $msg = $request->input('message'); - ModLogService::boot() - ->objectUid($user->id) - ->objectId($user->id) - ->objectType('App\User::class') - ->user($request->user()) - ->message($msg) - ->accessLevel('admin') - ->save(); - return redirect('/i/admin/users/modlogs/' . $user->id); - } - - public function userDelete(Request $request, $id) - { - $user = User::findOrFail($id); - $profile = $user->profile; - return view('admin.users.delete', compact('user', 'profile')); - } - - public function userDeleteProcess(Request $request, $id) - { - $user = User::findOrFail($id); - $profile = $user->profile; - - if(config('pixelfed.account_deletion') == false) { - abort(404); - } - - if($user->is_admin == true) { - $mid = $request->user()->id; - abort_if($user->id < $mid, 403); - } - - $ts = now()->addMonth(); - $user->status = 'delete'; - $profile->status = 'delete'; - $user->delete_after = $ts; - $profile->delete_after = $ts; - $user->save(); - $profile->save(); - - ModLogService::boot() - ->objectUid($user->id) - ->objectId($user->id) - ->objectType('App\User::class') - ->user($request->user()) - ->action('admin.user.delete') - ->accessLevel('admin') - ->save(); - - Cache::forget('profiles:private'); - DeleteAccountPipeline::dispatch($user); - - $msg = "Successfully deleted {$user->username}!"; - $request->session()->flash('status', $msg); - return redirect('/i/admin/users/list'); - } - - public function userModerate(Request $request) - { - $this->validate($request, [ - 'profile_id' => 'required|exists:profiles,id', - 'action' => 'required|in:cw,no_autolink,unlisted' - ]); - - $pid = $request->input('profile_id'); - $action = $request->input('action'); - $profile = Profile::findOrFail($pid); - - if($profile->user->is_admin == true) { - $mid = $request->user()->id; - abort_if($profile->user_id < $mid, 403); - } - - switch ($action) { - case 'cw': - $profile->cw = !$profile->cw; - $msg = "Success!"; - break; - - case 'no_autolink': - $profile->no_autolink = !$profile->no_autolink; - $msg = "Success!"; - break; - - case 'unlisted': - $profile->unlisted = !$profile->unlisted; - $msg = "Success!"; - break; - } - - $profile->save(); - - ModLogService::boot() - ->objectUid($profile->user_id) - ->objectId($profile->user_id) - ->objectType('App\User::class') - ->user($request->user()) - ->action('admin.user.moderate') - ->metadata([ - 'action' => $action, - 'message' => $msg - ]) - ->accessLevel('admin') - ->save(); - - $request->session()->flash('status', $msg); - return redirect('/i/admin/users/modtools/' . $profile->user_id); - } - - public function userModLogDelete(Request $request, $id) - { - $this->validate($request, [ - 'mid' => 'required|integer|exists:mod_logs,id' - ]); - $user = User::findOrFail($id); - $uid = $request->user()->id; - $mid = $request->input('mid'); - $ml = ModLog::whereUserId($uid)->findOrFail($mid)->delete(); - $msg = "Successfully deleted modlog comment!"; - $request->session()->flash('status', $msg); - return redirect('/i/admin/users/modlogs/' . $user->id); - } + public function users(Request $request) + { + $search = $request->has('a') && $request->query('a') == 'search' ? $request->query('q') : null; + $col = $request->query('col', 'id'); + $dir = $request->query('dir', 'desc'); + $offset = $request->has('page') ? (int) $request->input('page') : 0; + $limit = (int) $request->query('limit', 10); + $trashed = $request->has('trashed'); + + $queryParams = []; + if ($search) { + $queryParams['a'] = 'search'; + $queryParams['q'] = $search; + } + if ($request->has('col')) { + $queryParams['col'] = $col; + } + if ($request->has('dir')) { + $queryParams['dir'] = $dir; + } + if ($request->has('limit')) { + $queryParams['limit'] = $limit; + } + if ($trashed) { + $queryParams['trashed'] = '1'; + } + + $queryString = ! empty($queryParams) ? '&'.http_build_query($queryParams) : ''; + + $pagination = [ + 'prev' => $offset > 0 ? $offset - 1 : null, + 'next' => $offset + 1, + 'query' => $queryString, + ]; + + $users = User::select('id', 'username', 'status', 'profile_id', 'is_admin') + ->orderBy($col, $dir) + ->when($search, function ($q, $search) { + return $q->where('username', 'like', "%{$search}%"); + }) + ->when($offset > 0, function ($q) use ($offset, $limit) { + return $q->offset($offset * $limit); + }) + ->when($trashed, function ($q) { + return $q->where('status', 'deleted')->orWhereNotNull('delete_after'); + }, function ($q) { + return $q->whereNull('status')->whereNull('delete_after'); + }) + ->limit($limit) + ->get() + ->map(function ($u) { + $u['account'] = AccountService::get($u->profile_id, true); + + return $u; + }); + + return view('admin.users.home', compact('users', 'pagination', 'search', 'col', 'dir', 'limit', 'trashed')); + } + + public function userShow(Request $request, $id) + { + $user = User::findOrFail($id); + $profile = $user->profile; + + return view('admin.users.show', compact('user', 'profile')); + } + + public function userEdit(Request $request, $id) + { + $user = User::findOrFail($id); + $profile = $user->profile; + + return view('admin.users.edit', compact('user', 'profile')); + } + + public function userEditSubmit(Request $request, $id) + { + $user = User::findOrFail($id); + $profile = $user->profile; + $changed = false; + $fields = []; + + if ($request->filled('name') && $request->input('name') != $user->name) { + $fields['name'] = ['old' => $user->name, 'new' => $request->input('name')]; + $user->name = $profile->name = $request->input('name'); + $changed = true; + } + if ($request->filled('username') && $request->input('username') != $user->username) { + $fields['username'] = ['old' => $user->username, 'new' => $request->input('username')]; + $user->username = $profile->username = $request->input('username'); + $changed = true; + } + if ($request->filled('email') && $request->input('email') != $user->email) { + if (filter_var($request->input('email'), FILTER_VALIDATE_EMAIL) == false) { + abort(500, 'Invalid email address'); + } + $fields['email'] = ['old' => $user->email, 'new' => $request->input('email')]; + $user->email = $request->input('email'); + $changed = true; + } + if ($request->input('bio') != $profile->bio) { + $fields['bio'] = ['old' => $user->bio, 'new' => $request->input('bio')]; + $profile->bio = $request->input('bio'); + $changed = true; + } + if ($request->input('website') != $profile->website) { + $fields['website'] = ['old' => $user->website, 'new' => $request->input('website')]; + $profile->website = $request->input('website'); + $changed = true; + } + + if ($changed == true) { + ModLogService::boot() + ->objectUid($user->id) + ->objectId($user->id) + ->objectType('App\User::class') + ->user($request->user()) + ->action('admin.user.edit') + ->metadata([ + 'fields' => $fields, + ]) + ->accessLevel('admin') + ->save(); + $profile->save(); + $user->save(); + } + + return redirect('/i/admin/users/show/'.$user->id); + } + + public function userActivity(Request $request, $id) + { + $user = User::findOrFail($id); + $profile = $user->profile; + $logs = $user->accountLog()->orderByDesc('created_at')->paginate(10); + + return view('admin.users.activity', compact('user', 'profile', 'logs')); + } + + public function userMessage(Request $request, $id) + { + $user = User::findOrFail($id); + $profile = $user->profile; + + return view('admin.users.message', compact('user', 'profile')); + } + + public function userMessageSend(Request $request, $id) + { + $this->validate($request, [ + 'message' => 'required|string|min:5|max:500', + ]); + $user = User::findOrFail($id); + $profile = $user->profile; + $message = $request->input('message'); + Mail::to($user->email)->send(new AdminMessage($message)); + ModLogService::boot() + ->objectUid($user->id) + ->objectId($user->id) + ->objectType('App\User::class') + ->user($request->user()) + ->action('admin.user.mail') + ->metadata([ + 'message' => $message, + ]) + ->accessLevel('admin') + ->save(); + + return redirect('/i/admin/users/show/'.$user->id); + } + + public function userModTools(Request $request, $id) + { + $user = User::findOrFail($id); + $profile = $user->profile; + + return view('admin.users.modtools', compact('user', 'profile')); + } + + public function userModLogs(Request $request, $id) + { + $user = User::findOrFail($id); + $profile = $user->profile; + $logs = ModLog::whereObjectUid($user->id) + ->orderByDesc('created_at') + ->simplePaginate(10); + + return view('admin.users.modlogs', compact('user', 'profile', 'logs')); + } + + public function userModLogsMessage(Request $request, $id) + { + $this->validate($request, [ + 'message' => 'required|string|min:5|max:500', + ]); + $user = User::findOrFail($id); + $profile = $user->profile; + $msg = $request->input('message'); + ModLogService::boot() + ->objectUid($user->id) + ->objectId($user->id) + ->objectType('App\User::class') + ->user($request->user()) + ->message($msg) + ->accessLevel('admin') + ->save(); + + return redirect('/i/admin/users/modlogs/'.$user->id); + } + + public function userDelete(Request $request, $id) + { + $user = User::findOrFail($id); + $profile = $user->profile; + + return view('admin.users.delete', compact('user', 'profile')); + } + + public function userDeleteProcess(Request $request, $id) + { + $user = User::findOrFail($id); + $profile = $user->profile; + + if (config('pixelfed.account_deletion') == false) { + abort(404); + } + + if ($user->is_admin == true) { + $mid = $request->user()->id; + abort_if($user->id < $mid, 403); + } + + $ts = now()->addMonth(); + $user->status = 'delete'; + $profile->status = 'delete'; + $user->delete_after = $ts; + $profile->delete_after = $ts; + $user->save(); + $profile->save(); + + ModLogService::boot() + ->objectUid($user->id) + ->objectId($user->id) + ->objectType('App\User::class') + ->user($request->user()) + ->action('admin.user.delete') + ->accessLevel('admin') + ->save(); + + Cache::forget('profiles:private'); + DeleteAccountPipeline::dispatch($user); + + $msg = "Successfully deleted {$user->username}!"; + $request->session()->flash('status', $msg); + + return redirect('/i/admin/users/list'); + } + + public function userModerate(Request $request) + { + $this->validate($request, [ + 'profile_id' => 'required|exists:profiles,id', + 'action' => 'required|in:cw,no_autolink,unlisted', + ]); + + $pid = $request->input('profile_id'); + $action = $request->input('action'); + $profile = Profile::findOrFail($pid); + + if ($profile->user->is_admin == true) { + $mid = $request->user()->id; + abort_if($profile->user_id < $mid, 403); + } + + switch ($action) { + case 'cw': + $profile->cw = ! $profile->cw; + $msg = 'Success!'; + break; + + case 'no_autolink': + $profile->no_autolink = ! $profile->no_autolink; + $msg = 'Success!'; + break; + + case 'unlisted': + $profile->unlisted = ! $profile->unlisted; + $msg = 'Success!'; + break; + } + + $profile->save(); + + ModLogService::boot() + ->objectUid($profile->user_id) + ->objectId($profile->user_id) + ->objectType('App\User::class') + ->user($request->user()) + ->action('admin.user.moderate') + ->metadata([ + 'action' => $action, + 'message' => $msg, + ]) + ->accessLevel('admin') + ->save(); + + $request->session()->flash('status', $msg); + + return redirect('/i/admin/users/modtools/'.$profile->user_id); + } + + public function userModLogDelete(Request $request, $id) + { + $this->validate($request, [ + 'mid' => 'required|integer|exists:mod_logs,id', + ]); + $user = User::findOrFail($id); + $uid = $request->user()->id; + $mid = $request->input('mid'); + $ml = ModLog::whereUserId($uid)->findOrFail($mid)->delete(); + $msg = 'Successfully deleted modlog comment!'; + $request->session()->flash('status', $msg); + + return redirect('/i/admin/users/modlogs/'.$user->id); + } } diff --git a/resources/views/admin/users/home.blade.php b/resources/views/admin/users/home.blade.php index 70ab654a1..c5ed54c99 100644 --- a/resources/views/admin/users/home.blade.php +++ b/resources/views/admin/users/home.blade.php @@ -1,281 +1,636 @@ @extends('admin.partial.template-full') @section('section') -
-

Users

-
- -
- -
- -
-
-
-
-
-
- -
-
- - - - - - - - - - - - - - @foreach($users as $key => $user) - @if($user->status == 'deleted') - - - - - - - - - - @else - - - - - - - - - - @endif - @endforeach - -
- - - ID - - Username - - Statuses - - Followers - - Following - - Actions -
- - - {{$user->id}} - - - - - {{$user->username}} - - 000 - - Account Deleted - -
- - - {{$user->id}} - - @if($user->account) - - @endif - - {{$user->username}} - @if($user->is_admin) - - @endif - - - @if($user->account) - {{$user->account['statuses_count']}} - @else - 0 - @endif - - @if($user->account) - {{$user->account['followers_count']}} - @else - 0 - @endif - - @if($user->account) - {{$user->account['following_count']}} - @else - 0 - @endif - - - - Profile - - - - Review - - - - Mod Tools - - @if($user->status !== 'deleted' && !$user->is_admin) - - Delete - - @endif - -
-
-
- +
+
+
+
+ Users +
+

Manage and moderate user accounts

+
+
+
+ + @if(request()->has('col'))@endif + @if(request()->has('dir'))@endif + @if(request()->has('limit'))@endif + @if(request()->has('trashed'))@endif +
+
+ + + +
+ +
+ +
+
+
+
+
+ +
+
+
+
+
+
+ + +
+ +
+ + +
+
+
+ +
+
+
+ + 0 selected +
+ +
+
+
+
+
+ +
+
+ + + + + + + + + + + + + + @forelse($users as $key => $user) + @if(str_starts_with($user->status, 'delete')) + + + + + + + + + + @else + + + + + + + + + + @endif + @empty + + + + @endforelse + +
+
+ + +
+
+ + ID + + + + + Username + + + + Posts + + Followers + + Following + + Actions +
+
+ + +
+
+ {{$user->id}} + +
+
+ +
+
+
{{$user->username}}
+ Account deleted +
+
+
+ + + Deleted + +
+
+ + +
+
+ + {{$user->id}} + + +
+ +
+ @if($user->account) + +
+ @else + +
+ @endif +
+
+
+
+ +
+ {{$user->username}} + @if($user->is_admin) + + Admin + + @endif +
+
+ {{ str_limit(strip_tags($user->profile->bio))}} + {{ parse_url($user->profile->website, PHP_URL_HOST) }} +
+
+
+ + {{$user->account['statuses_count'] ?? 0}} + + + + {{$user->account['followers_count'] ?? 0}} + + + + {{$user->account['following_count'] ?? 0}} + + +
+ + + Moderate + + @if($user->status !== 'deleted' && !$user->is_admin) + + @endif +
+
+
+ +
No users found
+

+ @if(request()->input('q')) + Try adjusting your search criteria + @else + No users match the current filters + @endif +

+
+
+
+ + @if($users->count() > 0) + + @endif +
@endsection @push('styles') @endpush + @push('scripts') @endpush