154 lines
4.8 KiB
PHP
154 lines
4.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Http\Controllers\Api\Admin;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\User;
|
|
use App\Support\UsernamePolicy;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
final class UsernameApprovalController extends Controller
|
|
{
|
|
public function pending(): JsonResponse
|
|
{
|
|
$rows = DB::table('username_approval_requests')
|
|
->where('status', 'pending')
|
|
->orderBy('created_at')
|
|
->get([
|
|
'id',
|
|
'user_id',
|
|
'requested_username',
|
|
'context',
|
|
'similar_to',
|
|
'payload',
|
|
'created_at',
|
|
]);
|
|
|
|
return response()->json(['data' => $rows], Response::HTTP_OK);
|
|
}
|
|
|
|
public function approve(int $id, Request $request): JsonResponse
|
|
{
|
|
$row = DB::table('username_approval_requests')->where('id', $id)->first();
|
|
if (! $row) {
|
|
return response()->json(['message' => 'Request not found.'], Response::HTTP_NOT_FOUND);
|
|
}
|
|
|
|
if ((string) $row->status !== 'pending') {
|
|
return response()->json(['message' => 'Request is not pending.'], Response::HTTP_UNPROCESSABLE_ENTITY);
|
|
}
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
DB::table('username_approval_requests')
|
|
->where('id', $id)
|
|
->update([
|
|
'status' => 'approved',
|
|
'reviewed_by' => (int) $request->user()->id,
|
|
'reviewed_at' => now(),
|
|
'review_note' => (string) $request->input('note', ''),
|
|
'updated_at' => now(),
|
|
]);
|
|
|
|
if ((string) $row->context === 'profile_update' && ! empty($row->user_id)) {
|
|
$this->applyProfileRename((int) $row->user_id, (string) $row->requested_username);
|
|
}
|
|
|
|
DB::commit();
|
|
} catch (\Throwable $e) {
|
|
DB::rollBack();
|
|
return response()->json(['message' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'id' => $id,
|
|
'status' => 'approved',
|
|
], Response::HTTP_OK);
|
|
}
|
|
|
|
public function reject(int $id, Request $request): JsonResponse
|
|
{
|
|
$affected = DB::table('username_approval_requests')
|
|
->where('id', $id)
|
|
->where('status', 'pending')
|
|
->update([
|
|
'status' => 'rejected',
|
|
'reviewed_by' => (int) $request->user()->id,
|
|
'reviewed_at' => now(),
|
|
'review_note' => (string) $request->input('note', ''),
|
|
'updated_at' => now(),
|
|
]);
|
|
|
|
if ($affected === 0) {
|
|
return response()->json(['message' => 'Request not found or not pending.'], Response::HTTP_NOT_FOUND);
|
|
}
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'id' => $id,
|
|
'status' => 'rejected',
|
|
], Response::HTTP_OK);
|
|
}
|
|
|
|
private function applyProfileRename(int $userId, string $requestedUsername): void
|
|
{
|
|
$user = User::query()->find($userId);
|
|
if (! $user) {
|
|
return;
|
|
}
|
|
|
|
$requested = UsernamePolicy::normalize($requestedUsername);
|
|
if ($requested === '') {
|
|
throw new \RuntimeException('Requested username is invalid.');
|
|
}
|
|
|
|
$exists = User::query()
|
|
->whereRaw('LOWER(username) = ?', [$requested])
|
|
->where('id', '!=', $userId)
|
|
->exists();
|
|
|
|
if ($exists) {
|
|
throw new \RuntimeException('Requested username is already taken.');
|
|
}
|
|
|
|
$old = UsernamePolicy::normalize((string) ($user->username ?? ''));
|
|
if ($old === $requested) {
|
|
return;
|
|
}
|
|
|
|
$user->username = $requested;
|
|
$user->username_changed_at = now();
|
|
if (Schema::hasColumn('users', 'last_username_change_at')) {
|
|
$user->last_username_change_at = now();
|
|
}
|
|
$user->save();
|
|
|
|
if ($old !== '') {
|
|
DB::table('username_history')->insert([
|
|
'user_id' => $userId,
|
|
'old_username' => $old,
|
|
'changed_at' => now(),
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]);
|
|
|
|
DB::table('username_redirects')->updateOrInsert(
|
|
['old_username' => $old],
|
|
[
|
|
'new_username' => $requested,
|
|
'user_id' => $userId,
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]
|
|
);
|
|
}
|
|
}
|
|
}
|