refactor:用 AdminApiList 统一后台列表类接口的响应格式
This commit is contained in:
@@ -4,7 +4,7 @@ namespace App\Http\Controllers\Api\V1\Admin\Audit;
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\AuditLog;
|
use App\Models\AuditLog;
|
||||||
use App\Support\ApiResponse;
|
use App\Support\AdminApiList;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
@@ -15,8 +15,7 @@ final class AuditLogIndexController extends Controller
|
|||||||
{
|
{
|
||||||
public function __invoke(Request $request): JsonResponse
|
public function __invoke(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$perPage = min(max((int) $request->integer('per_page', 25), 1), 100);
|
$p = AdminApiList::readPaging($request);
|
||||||
$page = max((int) $request->integer('page', 1), 1);
|
|
||||||
$module = trim((string) $request->query('module_code', ''));
|
$module = trim((string) $request->query('module_code', ''));
|
||||||
$action = trim((string) $request->query('action_code', ''));
|
$action = trim((string) $request->query('action_code', ''));
|
||||||
$operatorType = trim((string) $request->query('operator_type', ''));
|
$operatorType = trim((string) $request->query('operator_type', ''));
|
||||||
@@ -33,17 +32,9 @@ final class AuditLogIndexController extends Controller
|
|||||||
$q->where('operator_type', $operatorType);
|
$q->where('operator_type', $operatorType);
|
||||||
}
|
}
|
||||||
|
|
||||||
$paginator = $q->paginate($perPage, ['*'], 'page', $page);
|
$paginator = $q->paginate($p['perPage'], ['*'], 'page', $p['page']);
|
||||||
|
|
||||||
return ApiResponse::success([
|
return AdminApiList::json($paginator, fn (AuditLog $r) => $this->row($r));
|
||||||
'items' => collect($paginator->items())->map(fn (AuditLog $r) => $this->row($r))->all(),
|
|
||||||
'meta' => [
|
|
||||||
'current_page' => $paginator->currentPage(),
|
|
||||||
'per_page' => $paginator->perPage(),
|
|
||||||
'total' => $paginator->total(),
|
|
||||||
'last_page' => $paginator->lastPage(),
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array<string, mixed> */
|
/** @return array<string, mixed> */
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ namespace App\Http\Controllers\Api\V1\Admin\Config;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\OddsVersion;
|
use App\Models\OddsVersion;
|
||||||
use App\Services\Config\OddsStreamService;
|
use App\Services\Config\OddsStreamService;
|
||||||
|
use App\Support\AdminApiList;
|
||||||
use App\Support\AdminConfigPresenter;
|
use App\Support\AdminConfigPresenter;
|
||||||
use App\Support\ApiResponse;
|
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
@@ -15,19 +15,11 @@ final class OddsVersionIndexController extends Controller
|
|||||||
{
|
{
|
||||||
public function __invoke(Request $request, OddsStreamService $service): JsonResponse
|
public function __invoke(Request $request, OddsStreamService $service): JsonResponse
|
||||||
{
|
{
|
||||||
$perPage = min(max((int) $request->integer('per_page', 25), 1), 100);
|
$p = AdminApiList::readPaging($request);
|
||||||
$status = trim((string) $request->query('status', ''));
|
$status = trim((string) $request->query('status', ''));
|
||||||
|
|
||||||
$paginator = $service->paginate($status === '' ? null : $status, $perPage);
|
$paginator = $service->paginate($status === '' ? null : $status, $p['perPage'], $p['page']);
|
||||||
|
|
||||||
return ApiResponse::success([
|
return AdminApiList::json($paginator, fn (OddsVersion $v) => AdminConfigPresenter::oddsVersionSummary($v));
|
||||||
'items' => collect($paginator->items())->map(fn (OddsVersion $v) => AdminConfigPresenter::oddsVersionSummary($v))->all(),
|
|
||||||
'meta' => [
|
|
||||||
'current_page' => $paginator->currentPage(),
|
|
||||||
'per_page' => $paginator->perPage(),
|
|
||||||
'total' => $paginator->total(),
|
|
||||||
'last_page' => $paginator->lastPage(),
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ namespace App\Http\Controllers\Api\V1\Admin\Config;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\PlayConfigVersion;
|
use App\Models\PlayConfigVersion;
|
||||||
use App\Services\Config\PlayConfigStreamService;
|
use App\Services\Config\PlayConfigStreamService;
|
||||||
|
use App\Support\AdminApiList;
|
||||||
use App\Support\AdminConfigPresenter;
|
use App\Support\AdminConfigPresenter;
|
||||||
use App\Support\ApiResponse;
|
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
@@ -15,19 +15,11 @@ final class PlayConfigVersionIndexController extends Controller
|
|||||||
{
|
{
|
||||||
public function __invoke(Request $request, PlayConfigStreamService $service): JsonResponse
|
public function __invoke(Request $request, PlayConfigStreamService $service): JsonResponse
|
||||||
{
|
{
|
||||||
$perPage = min(max((int) $request->integer('per_page', 25), 1), 100);
|
$p = AdminApiList::readPaging($request);
|
||||||
$status = trim((string) $request->query('status', ''));
|
$status = trim((string) $request->query('status', ''));
|
||||||
|
|
||||||
$paginator = $service->paginate($status === '' ? null : $status, $perPage);
|
$paginator = $service->paginate($status === '' ? null : $status, $p['perPage'], $p['page']);
|
||||||
|
|
||||||
return ApiResponse::success([
|
return AdminApiList::json($paginator, fn (PlayConfigVersion $v) => AdminConfigPresenter::playConfigVersionSummary($v));
|
||||||
'items' => collect($paginator->items())->map(fn (PlayConfigVersion $v) => AdminConfigPresenter::playConfigVersionSummary($v))->all(),
|
|
||||||
'meta' => [
|
|
||||||
'current_page' => $paginator->currentPage(),
|
|
||||||
'per_page' => $paginator->perPage(),
|
|
||||||
'total' => $paginator->total(),
|
|
||||||
'last_page' => $paginator->lastPage(),
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ namespace App\Http\Controllers\Api\V1\Admin\Config;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\RiskCapVersion;
|
use App\Models\RiskCapVersion;
|
||||||
use App\Services\Config\RiskCapStreamService;
|
use App\Services\Config\RiskCapStreamService;
|
||||||
|
use App\Support\AdminApiList;
|
||||||
use App\Support\AdminConfigPresenter;
|
use App\Support\AdminConfigPresenter;
|
||||||
use App\Support\ApiResponse;
|
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
@@ -15,19 +15,11 @@ final class RiskCapVersionIndexController extends Controller
|
|||||||
{
|
{
|
||||||
public function __invoke(Request $request, RiskCapStreamService $service): JsonResponse
|
public function __invoke(Request $request, RiskCapStreamService $service): JsonResponse
|
||||||
{
|
{
|
||||||
$perPage = min(max((int) $request->integer('per_page', 25), 1), 100);
|
$p = AdminApiList::readPaging($request);
|
||||||
$status = trim((string) $request->query('status', ''));
|
$status = trim((string) $request->query('status', ''));
|
||||||
|
|
||||||
$paginator = $service->paginate($status === '' ? null : $status, $perPage);
|
$paginator = $service->paginate($status === '' ? null : $status, $p['perPage'], $p['page']);
|
||||||
|
|
||||||
return ApiResponse::success([
|
return AdminApiList::json($paginator, fn (RiskCapVersion $v) => AdminConfigPresenter::riskCapVersionSummary($v));
|
||||||
'items' => collect($paginator->items())->map(fn (RiskCapVersion $v) => AdminConfigPresenter::riskCapVersionSummary($v))->all(),
|
|
||||||
'meta' => [
|
|
||||||
'current_page' => $paginator->currentPage(),
|
|
||||||
'per_page' => $paginator->perPage(),
|
|
||||||
'total' => $paginator->total(),
|
|
||||||
'last_page' => $paginator->lastPage(),
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ namespace App\Http\Controllers\Api\V1\Admin\Draw;
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Draw;
|
use App\Models\Draw;
|
||||||
use App\Support\ApiResponse;
|
use App\Support\AdminApiList;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
@@ -16,7 +17,7 @@ final class AdminDrawIndexController extends Controller
|
|||||||
{
|
{
|
||||||
public function __invoke(Request $request): JsonResponse
|
public function __invoke(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$perPage = min(max((int) $request->integer('per_page', 25), 1), 100);
|
$p = AdminApiList::readPaging($request);
|
||||||
$drawNo = trim((string) $request->query('draw_no', ''));
|
$drawNo = trim((string) $request->query('draw_no', ''));
|
||||||
$status = trim((string) $request->query('status', ''));
|
$status = trim((string) $request->query('status', ''));
|
||||||
|
|
||||||
@@ -30,18 +31,10 @@ final class AdminDrawIndexController extends Controller
|
|||||||
$q->where('status', $status);
|
$q->where('status', $status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var \Illuminate\Contracts\Pagination\LengthAwarePaginator $paginator */
|
/** @var LengthAwarePaginator $paginator */
|
||||||
$paginator = $q->paginate($perPage);
|
$paginator = $q->paginate($p['perPage'], ['*'], 'page', $p['page']);
|
||||||
|
|
||||||
return ApiResponse::success([
|
return AdminApiList::json($paginator, fn (Draw $row) => $this->row($row));
|
||||||
'items' => collect($paginator->items())->map(fn (Draw $row) => $this->row($row))->all(),
|
|
||||||
'meta' => [
|
|
||||||
'current_page' => $paginator->currentPage(),
|
|
||||||
'per_page' => $paginator->perPage(),
|
|
||||||
'total' => $paginator->total(),
|
|
||||||
'last_page' => $paginator->lastPage(),
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array<string, mixed> */
|
/** @return array<string, mixed> */
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace App\Http\Controllers\Api\V1\Admin\Jackpot;
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\JackpotContribution;
|
use App\Models\JackpotContribution;
|
||||||
use App\Support\ApiResponse;
|
use App\Support\AdminApiList;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
@@ -15,8 +15,7 @@ final class AdminJackpotContributionIndexController extends Controller
|
|||||||
{
|
{
|
||||||
public function __invoke(Request $request): JsonResponse
|
public function __invoke(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$perPage = min(max((int) $request->integer('per_page', 25), 1), 100);
|
$p = AdminApiList::readPaging($request);
|
||||||
$page = max((int) $request->integer('page', 1), 1);
|
|
||||||
$drawNo = trim((string) $request->query('draw_no', ''));
|
$drawNo = trim((string) $request->query('draw_no', ''));
|
||||||
|
|
||||||
$q = JackpotContribution::query()
|
$q = JackpotContribution::query()
|
||||||
@@ -27,10 +26,9 @@ final class AdminJackpotContributionIndexController extends Controller
|
|||||||
$q->whereHas('draw', fn ($d) => $d->where('draw_no', 'like', '%'.$drawNo.'%'));
|
$q->whereHas('draw', fn ($d) => $d->where('draw_no', 'like', '%'.$drawNo.'%'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$paginator = $q->paginate($perPage, ['*'], 'page', $page);
|
$paginator = $q->paginate($p['perPage'], ['*'], 'page', $p['page']);
|
||||||
|
|
||||||
return ApiResponse::success([
|
return AdminApiList::json($paginator, fn (JackpotContribution $r) => [
|
||||||
'items' => collect($paginator->items())->map(fn (JackpotContribution $r) => [
|
|
||||||
'id' => (int) $r->id,
|
'id' => (int) $r->id,
|
||||||
'draw_id' => (int) $r->draw_id,
|
'draw_id' => (int) $r->draw_id,
|
||||||
'draw_no' => $r->draw?->draw_no,
|
'draw_no' => $r->draw?->draw_no,
|
||||||
@@ -42,13 +40,6 @@ final class AdminJackpotContributionIndexController extends Controller
|
|||||||
'ticket_no' => $r->ticketItem?->ticket_no,
|
'ticket_no' => $r->ticketItem?->ticket_no,
|
||||||
'contribution_amount' => (int) $r->contribution_amount,
|
'contribution_amount' => (int) $r->contribution_amount,
|
||||||
'created_at' => $r->created_at?->toIso8601String(),
|
'created_at' => $r->created_at?->toIso8601String(),
|
||||||
])->all(),
|
|
||||||
'meta' => [
|
|
||||||
'current_page' => $paginator->currentPage(),
|
|
||||||
'per_page' => $paginator->perPage(),
|
|
||||||
'total' => $paginator->total(),
|
|
||||||
'last_page' => $paginator->lastPage(),
|
|
||||||
],
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace App\Http\Controllers\Api\V1\Admin\Jackpot;
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\JackpotPayoutLog;
|
use App\Models\JackpotPayoutLog;
|
||||||
use App\Support\ApiResponse;
|
use App\Support\AdminApiList;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
@@ -15,8 +15,7 @@ final class AdminJackpotPayoutLogIndexController extends Controller
|
|||||||
{
|
{
|
||||||
public function __invoke(Request $request): JsonResponse
|
public function __invoke(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$perPage = min(max((int) $request->integer('per_page', 25), 1), 100);
|
$p = AdminApiList::readPaging($request);
|
||||||
$page = max((int) $request->integer('page', 1), 1);
|
|
||||||
$drawNo = trim((string) $request->query('draw_no', ''));
|
$drawNo = trim((string) $request->query('draw_no', ''));
|
||||||
|
|
||||||
$q = JackpotPayoutLog::query()
|
$q = JackpotPayoutLog::query()
|
||||||
@@ -27,10 +26,9 @@ final class AdminJackpotPayoutLogIndexController extends Controller
|
|||||||
$q->whereHas('draw', fn ($d) => $d->where('draw_no', 'like', '%'.$drawNo.'%'));
|
$q->whereHas('draw', fn ($d) => $d->where('draw_no', 'like', '%'.$drawNo.'%'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$paginator = $q->paginate($perPage, ['*'], 'page', $page);
|
$paginator = $q->paginate($p['perPage'], ['*'], 'page', $p['page']);
|
||||||
|
|
||||||
return ApiResponse::success([
|
return AdminApiList::json($paginator, fn (JackpotPayoutLog $r) => [
|
||||||
'items' => collect($paginator->items())->map(fn (JackpotPayoutLog $r) => [
|
|
||||||
'id' => (int) $r->id,
|
'id' => (int) $r->id,
|
||||||
'draw_id' => (int) $r->draw_id,
|
'draw_id' => (int) $r->draw_id,
|
||||||
'draw_no' => $r->draw?->draw_no,
|
'draw_no' => $r->draw?->draw_no,
|
||||||
@@ -41,13 +39,6 @@ final class AdminJackpotPayoutLogIndexController extends Controller
|
|||||||
'winner_count' => (int) $r->winner_count,
|
'winner_count' => (int) $r->winner_count,
|
||||||
'trigger_snapshot_json' => $r->trigger_snapshot_json,
|
'trigger_snapshot_json' => $r->trigger_snapshot_json,
|
||||||
'created_at' => $r->created_at?->toIso8601String(),
|
'created_at' => $r->created_at?->toIso8601String(),
|
||||||
])->all(),
|
|
||||||
'meta' => [
|
|
||||||
'current_page' => $paginator->currentPage(),
|
|
||||||
'per_page' => $paginator->perPage(),
|
|
||||||
'total' => $paginator->total(),
|
|
||||||
'last_page' => $paginator->lastPage(),
|
|
||||||
],
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace App\Http\Controllers\Api\V1\Admin\Reconcile;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\ReconcileItem;
|
use App\Models\ReconcileItem;
|
||||||
use App\Models\ReconcileJob;
|
use App\Models\ReconcileJob;
|
||||||
use App\Support\ApiResponse;
|
use App\Support\AdminApiList;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
@@ -14,17 +14,13 @@ final class ReconcileItemIndexController extends Controller
|
|||||||
{
|
{
|
||||||
public function __invoke(Request $request, ReconcileJob $reconcile_job): JsonResponse
|
public function __invoke(Request $request, ReconcileJob $reconcile_job): JsonResponse
|
||||||
{
|
{
|
||||||
$perPage = min(max((int) $request->integer('per_page', 50), 1), 200);
|
$p = AdminApiList::readPaging($request, 50, 200);
|
||||||
$page = max((int) $request->integer('page', 1), 1);
|
|
||||||
|
|
||||||
$paginator = $reconcile_job->items()
|
$paginator = $reconcile_job->items()
|
||||||
->orderBy('id')
|
->orderBy('id')
|
||||||
->paginate($perPage, ['*'], 'page', $page);
|
->paginate($p['perPage'], ['*'], 'page', $p['page']);
|
||||||
|
|
||||||
return ApiResponse::success([
|
return AdminApiList::jsonWith($paginator, fn (ReconcileItem $r) => [
|
||||||
'job_id' => (int) $reconcile_job->id,
|
|
||||||
'job_no' => $reconcile_job->job_no,
|
|
||||||
'items' => collect($paginator->items())->map(fn (ReconcileItem $r) => [
|
|
||||||
'id' => (int) $r->id,
|
'id' => (int) $r->id,
|
||||||
'side_a_ref' => $r->side_a_ref,
|
'side_a_ref' => $r->side_a_ref,
|
||||||
'side_b_ref' => $r->side_b_ref,
|
'side_b_ref' => $r->side_b_ref,
|
||||||
@@ -32,13 +28,9 @@ final class ReconcileItemIndexController extends Controller
|
|||||||
'status' => $r->status,
|
'status' => $r->status,
|
||||||
'resolved_at' => $r->resolved_at?->toIso8601String(),
|
'resolved_at' => $r->resolved_at?->toIso8601String(),
|
||||||
'created_at' => $r->created_at?->toIso8601String(),
|
'created_at' => $r->created_at?->toIso8601String(),
|
||||||
])->all(),
|
], [
|
||||||
'meta' => [
|
'job_id' => (int) $reconcile_job->id,
|
||||||
'current_page' => $paginator->currentPage(),
|
'job_no' => $reconcile_job->job_no,
|
||||||
'per_page' => $paginator->perPage(),
|
|
||||||
'total' => $paginator->total(),
|
|
||||||
'last_page' => $paginator->lastPage(),
|
|
||||||
],
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace App\Http\Controllers\Api\V1\Admin\Reconcile;
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\ReconcileJob;
|
use App\Models\ReconcileJob;
|
||||||
use App\Support\ApiResponse;
|
use App\Support\AdminApiList;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
@@ -13,8 +13,7 @@ final class ReconcileJobIndexController extends Controller
|
|||||||
{
|
{
|
||||||
public function __invoke(Request $request): JsonResponse
|
public function __invoke(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$perPage = min(max((int) $request->integer('per_page', 25), 1), 100);
|
$p = AdminApiList::readPaging($request);
|
||||||
$page = max((int) $request->integer('page', 1), 1);
|
|
||||||
$type = trim((string) $request->query('reconcile_type', ''));
|
$type = trim((string) $request->query('reconcile_type', ''));
|
||||||
|
|
||||||
$q = ReconcileJob::query()->orderByDesc('id');
|
$q = ReconcileJob::query()->orderByDesc('id');
|
||||||
@@ -22,17 +21,9 @@ final class ReconcileJobIndexController extends Controller
|
|||||||
$q->where('reconcile_type', $type);
|
$q->where('reconcile_type', $type);
|
||||||
}
|
}
|
||||||
|
|
||||||
$paginator = $q->paginate($perPage, ['*'], 'page', $page);
|
$paginator = $q->paginate($p['perPage'], ['*'], 'page', $p['page']);
|
||||||
|
|
||||||
return ApiResponse::success([
|
return AdminApiList::json($paginator, fn (ReconcileJob $j) => $this->row($j));
|
||||||
'items' => collect($paginator->items())->map(fn (ReconcileJob $j) => $this->row($j))->all(),
|
|
||||||
'meta' => [
|
|
||||||
'current_page' => $paginator->currentPage(),
|
|
||||||
'per_page' => $paginator->perPage(),
|
|
||||||
'total' => $paginator->total(),
|
|
||||||
'last_page' => $paginator->lastPage(),
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array<string, mixed> */
|
/** @return array<string, mixed> */
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace App\Http\Controllers\Api\V1\Admin\Reports;
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\ReportJob;
|
use App\Models\ReportJob;
|
||||||
use App\Support\ApiResponse;
|
use App\Support\AdminApiList;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
@@ -13,22 +13,13 @@ final class ReportJobIndexController extends Controller
|
|||||||
{
|
{
|
||||||
public function __invoke(Request $request): JsonResponse
|
public function __invoke(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$perPage = min(max((int) $request->integer('per_page', 25), 1), 100);
|
$p = AdminApiList::readPaging($request);
|
||||||
$page = max((int) $request->integer('page', 1), 1);
|
|
||||||
|
|
||||||
$paginator = ReportJob::query()
|
$paginator = ReportJob::query()
|
||||||
->orderByDesc('id')
|
->orderByDesc('id')
|
||||||
->paginate($perPage, ['*'], 'page', $page);
|
->paginate($p['perPage'], ['*'], 'page', $p['page']);
|
||||||
|
|
||||||
return ApiResponse::success([
|
return AdminApiList::json($paginator, fn (ReportJob $j) => $this->row($j));
|
||||||
'items' => collect($paginator->items())->map(fn (ReportJob $j) => $this->row($j))->all(),
|
|
||||||
'meta' => [
|
|
||||||
'current_page' => $paginator->currentPage(),
|
|
||||||
'per_page' => $paginator->perPage(),
|
|
||||||
'total' => $paginator->total(),
|
|
||||||
'last_page' => $paginator->lastPage(),
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array<string, mixed> */
|
/** @return array<string, mixed> */
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace App\Http\Controllers\Api\V1\Admin\Risk;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Draw;
|
use App\Models\Draw;
|
||||||
use App\Models\RiskPool;
|
use App\Models\RiskPool;
|
||||||
use App\Support\ApiResponse;
|
use App\Support\AdminApiList;
|
||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@@ -19,7 +19,7 @@ final class AdminRiskPoolIndexController extends Controller
|
|||||||
{
|
{
|
||||||
public function __invoke(Request $request, Draw $draw): JsonResponse
|
public function __invoke(Request $request, Draw $draw): JsonResponse
|
||||||
{
|
{
|
||||||
$perPage = min(max((int) $request->integer('per_page', 25), 1), 100);
|
$p = AdminApiList::readPaging($request);
|
||||||
$soldOutOnly = $request->boolean('sold_out_only');
|
$soldOutOnly = $request->boolean('sold_out_only');
|
||||||
$sort = trim((string) $request->query('sort', 'usage_desc'));
|
$sort = trim((string) $request->query('sort', 'usage_desc'));
|
||||||
|
|
||||||
@@ -39,18 +39,11 @@ final class AdminRiskPoolIndexController extends Controller
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** @var LengthAwarePaginator $paginator */
|
/** @var LengthAwarePaginator $paginator */
|
||||||
$paginator = $q->paginate($perPage);
|
$paginator = $q->paginate($p['perPage'], ['*'], 'page', $p['page']);
|
||||||
|
|
||||||
return ApiResponse::success([
|
return AdminApiList::jsonWith($paginator, fn (RiskPool $row) => $this->row($row), [
|
||||||
'draw_id' => (int) $draw->id,
|
'draw_id' => (int) $draw->id,
|
||||||
'draw_no' => $draw->draw_no,
|
'draw_no' => $draw->draw_no,
|
||||||
'items' => collect($paginator->items())->map(fn (RiskPool $row) => $this->row($row))->all(),
|
|
||||||
'meta' => [
|
|
||||||
'current_page' => $paginator->currentPage(),
|
|
||||||
'per_page' => $paginator->perPage(),
|
|
||||||
'total' => $paginator->total(),
|
|
||||||
'last_page' => $paginator->lastPage(),
|
|
||||||
],
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace App\Http\Controllers\Api\V1\Admin\Risk;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\Draw;
|
use App\Models\Draw;
|
||||||
use App\Models\RiskPoolLockLog;
|
use App\Models\RiskPoolLockLog;
|
||||||
use App\Support\ApiResponse;
|
use App\Support\AdminApiList;
|
||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@@ -17,7 +17,7 @@ final class AdminRiskPoolLockLogIndexController extends Controller
|
|||||||
{
|
{
|
||||||
public function __invoke(Request $request, Draw $draw): JsonResponse
|
public function __invoke(Request $request, Draw $draw): JsonResponse
|
||||||
{
|
{
|
||||||
$perPage = min(max((int) $request->integer('per_page', 25), 1), 100);
|
$p = AdminApiList::readPaging($request);
|
||||||
$action = trim((string) $request->query('action_type', ''));
|
$action = trim((string) $request->query('action_type', ''));
|
||||||
$number = trim((string) $request->query('normalized_number', ''));
|
$number = trim((string) $request->query('normalized_number', ''));
|
||||||
|
|
||||||
@@ -36,18 +36,11 @@ final class AdminRiskPoolLockLogIndexController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @var LengthAwarePaginator $paginator */
|
/** @var LengthAwarePaginator $paginator */
|
||||||
$paginator = $q->paginate($perPage);
|
$paginator = $q->paginate($p['perPage'], ['*'], 'page', $p['page']);
|
||||||
|
|
||||||
return ApiResponse::success([
|
return AdminApiList::jsonWith($paginator, fn (RiskPoolLockLog $log) => $this->row($log), [
|
||||||
'draw_id' => (int) $draw->id,
|
'draw_id' => (int) $draw->id,
|
||||||
'draw_no' => $draw->draw_no,
|
'draw_no' => $draw->draw_no,
|
||||||
'items' => collect($paginator->items())->map(fn (RiskPoolLockLog $log) => $this->row($log))->all(),
|
|
||||||
'meta' => [
|
|
||||||
'current_page' => $paginator->currentPage(),
|
|
||||||
'per_page' => $paginator->perPage(),
|
|
||||||
'total' => $paginator->total(),
|
|
||||||
'last_page' => $paginator->lastPage(),
|
|
||||||
],
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use App\Lottery\ErrorCode;
|
|||||||
use App\Models\Draw;
|
use App\Models\Draw;
|
||||||
use App\Models\RiskPool;
|
use App\Models\RiskPool;
|
||||||
use App\Models\RiskPoolLockLog;
|
use App\Models\RiskPoolLockLog;
|
||||||
|
use App\Support\AdminApiList;
|
||||||
use App\Support\ApiResponse;
|
use App\Support\ApiResponse;
|
||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
@@ -32,7 +33,7 @@ final class AdminRiskPoolShowController extends Controller
|
|||||||
return ApiResponse::error('该期尚无此号码的风险池记录', ErrorCode::NotFound->value, null, 404);
|
return ApiResponse::error('该期尚无此号码的风险池记录', ErrorCode::NotFound->value, null, 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
$perPage = min(max((int) $request->integer('per_page', 20), 1), 100);
|
$p = AdminApiList::readPaging($request, 20, AdminApiList::MAX_PER_PAGE);
|
||||||
|
|
||||||
/** @var LengthAwarePaginator $paginator */
|
/** @var LengthAwarePaginator $paginator */
|
||||||
$paginator = RiskPoolLockLog::query()
|
$paginator = RiskPoolLockLog::query()
|
||||||
@@ -41,7 +42,7 @@ final class AdminRiskPoolShowController extends Controller
|
|||||||
->with(['ticketItem:id,ticket_no,play_code,player_id'])
|
->with(['ticketItem:id,ticket_no,play_code,player_id'])
|
||||||
->orderByDesc('created_at')
|
->orderByDesc('created_at')
|
||||||
->orderByDesc('id')
|
->orderByDesc('id')
|
||||||
->paginate($perPage);
|
->paginate($p['perPage'], ['*'], 'page', $p['page']);
|
||||||
|
|
||||||
$cap = (int) $pool->total_cap_amount;
|
$cap = (int) $pool->total_cap_amount;
|
||||||
$locked = (int) $pool->locked_amount;
|
$locked = (int) $pool->locked_amount;
|
||||||
@@ -59,15 +60,7 @@ final class AdminRiskPoolShowController extends Controller
|
|||||||
'usage_ratio' => $cap > 0 ? round($locked / $cap, 6) : null,
|
'usage_ratio' => $cap > 0 ? round($locked / $cap, 6) : null,
|
||||||
'version' => (int) $pool->version,
|
'version' => (int) $pool->version,
|
||||||
],
|
],
|
||||||
'logs' => [
|
'logs' => AdminApiList::payload($paginator, fn (RiskPoolLockLog $log) => $this->logRow($log)),
|
||||||
'items' => collect($paginator->items())->map(fn (RiskPoolLockLog $log) => $this->logRow($log))->all(),
|
|
||||||
'meta' => [
|
|
||||||
'current_page' => $paginator->currentPage(),
|
|
||||||
'per_page' => $paginator->perPage(),
|
|
||||||
'total' => $paginator->total(),
|
|
||||||
'last_page' => $paginator->lastPage(),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace App\Http\Controllers\Api\V1\Admin\Settlement;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\SettlementBatch;
|
use App\Models\SettlementBatch;
|
||||||
use App\Models\TicketSettlementDetail;
|
use App\Models\TicketSettlementDetail;
|
||||||
use App\Support\ApiResponse;
|
use App\Support\AdminApiList;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
@@ -16,8 +16,7 @@ final class AdminSettlementBatchDetailsController extends Controller
|
|||||||
{
|
{
|
||||||
public function __invoke(Request $request, SettlementBatch $batch): JsonResponse
|
public function __invoke(Request $request, SettlementBatch $batch): JsonResponse
|
||||||
{
|
{
|
||||||
$perPage = min(max((int) $request->integer('per_page', 25), 1), 100);
|
$p = AdminApiList::readPaging($request);
|
||||||
$page = max((int) $request->integer('page', 1), 1);
|
|
||||||
|
|
||||||
$paginator = TicketSettlementDetail::query()
|
$paginator = TicketSettlementDetail::query()
|
||||||
->where('settlement_batch_id', $batch->id)
|
->where('settlement_batch_id', $batch->id)
|
||||||
@@ -26,11 +25,9 @@ final class AdminSettlementBatchDetailsController extends Controller
|
|||||||
'ticketItem.player:id,username,site_player_id',
|
'ticketItem.player:id,username,site_player_id',
|
||||||
])
|
])
|
||||||
->orderBy('id')
|
->orderBy('id')
|
||||||
->paginate($perPage, ['*'], 'page', $page);
|
->paginate($p['perPage'], ['*'], 'page', $p['page']);
|
||||||
|
|
||||||
return ApiResponse::success([
|
return AdminApiList::jsonWith($paginator, function ($row) {
|
||||||
'batch_id' => (int) $batch->id,
|
|
||||||
'items' => collect($paginator->items())->map(function ($row) {
|
|
||||||
/** @var TicketSettlementDetail $row */
|
/** @var TicketSettlementDetail $row */
|
||||||
$item = $row->ticketItem;
|
$item = $row->ticketItem;
|
||||||
$player = $item?->player;
|
$player = $item?->player;
|
||||||
@@ -49,13 +46,6 @@ final class AdminSettlementBatchDetailsController extends Controller
|
|||||||
'match_detail_json' => $row->match_detail_json,
|
'match_detail_json' => $row->match_detail_json,
|
||||||
'created_at' => $row->created_at?->toIso8601String(),
|
'created_at' => $row->created_at?->toIso8601String(),
|
||||||
];
|
];
|
||||||
})->all(),
|
}, ['batch_id' => (int) $batch->id]);
|
||||||
'meta' => [
|
|
||||||
'current_page' => $paginator->currentPage(),
|
|
||||||
'per_page' => $paginator->perPage(),
|
|
||||||
'total' => $paginator->total(),
|
|
||||||
'last_page' => $paginator->lastPage(),
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace App\Http\Controllers\Api\V1\Admin\Settlement;
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\SettlementBatch;
|
use App\Models\SettlementBatch;
|
||||||
use App\Support\ApiResponse;
|
use App\Support\AdminApiList;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
@@ -15,8 +15,7 @@ final class AdminSettlementBatchIndexController extends Controller
|
|||||||
{
|
{
|
||||||
public function __invoke(Request $request): JsonResponse
|
public function __invoke(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$perPage = min(max((int) $request->integer('per_page', 25), 1), 100);
|
$p = AdminApiList::readPaging($request);
|
||||||
$page = max((int) $request->integer('page', 1), 1);
|
|
||||||
$drawNo = trim((string) $request->query('draw_no', ''));
|
$drawNo = trim((string) $request->query('draw_no', ''));
|
||||||
$status = trim((string) $request->query('status', ''));
|
$status = trim((string) $request->query('status', ''));
|
||||||
|
|
||||||
@@ -32,17 +31,9 @@ final class AdminSettlementBatchIndexController extends Controller
|
|||||||
$q->where('status', $status);
|
$q->where('status', $status);
|
||||||
}
|
}
|
||||||
|
|
||||||
$paginator = $q->paginate($perPage, ['*'], 'page', $page);
|
$paginator = $q->paginate($p['perPage'], ['*'], 'page', $p['page']);
|
||||||
|
|
||||||
return ApiResponse::success([
|
return AdminApiList::json($paginator, fn (SettlementBatch $b) => $this->row($b));
|
||||||
'items' => collect($paginator->items())->map(fn (SettlementBatch $b) => $this->row($b))->all(),
|
|
||||||
'meta' => [
|
|
||||||
'current_page' => $paginator->currentPage(),
|
|
||||||
'per_page' => $paginator->perPage(),
|
|
||||||
'total' => $paginator->total(),
|
|
||||||
'last_page' => $paginator->lastPage(),
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return array<string, mixed> */
|
/** @return array<string, mixed> */
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api\V1\Admin\User;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Lottery\ErrorCode;
|
||||||
|
use App\Models\AdminUser;
|
||||||
|
use App\Services\AuditLogger;
|
||||||
|
use App\Support\AdminUserApiPresenter;
|
||||||
|
use App\Support\ApiResponse;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
/** DELETE /api/v1/admin/admin-users/{admin_user} */
|
||||||
|
final class AdminUserDestroyController extends Controller
|
||||||
|
{
|
||||||
|
public function __invoke(Request $request, AdminUser $admin_user): JsonResponse
|
||||||
|
{
|
||||||
|
/** @var AdminUser $actor */
|
||||||
|
$actor = $request->lotteryAdmin();
|
||||||
|
|
||||||
|
if ((int) $actor->getKey() === (int) $admin_user->getKey()) {
|
||||||
|
return ApiResponse::error(
|
||||||
|
'不能删除当前登录账号',
|
||||||
|
ErrorCode::ValidationFailed->value,
|
||||||
|
null,
|
||||||
|
422,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$admin_user->load('roles');
|
||||||
|
if ($admin_user->isSuperAdmin()) {
|
||||||
|
$hasOther = AdminUser::query()
|
||||||
|
->whereKeyNot($admin_user->getKey())
|
||||||
|
->whereHas('roles', static fn ($q) => $q->where('admin_roles.slug', AdminUser::ROLE_SUPER_ADMIN))
|
||||||
|
->exists();
|
||||||
|
if (! $hasOther) {
|
||||||
|
return ApiResponse::error(
|
||||||
|
'不能删除最后一个超级管理员',
|
||||||
|
ErrorCode::ValidationFailed->value,
|
||||||
|
null,
|
||||||
|
422,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$before = AdminUserApiPresenter::listItem($admin_user);
|
||||||
|
$id = (int) $admin_user->id;
|
||||||
|
$admin_user->delete();
|
||||||
|
|
||||||
|
AuditLogger::recordForAdmin(
|
||||||
|
$actor,
|
||||||
|
$request,
|
||||||
|
'system',
|
||||||
|
'admin_user.delete',
|
||||||
|
'admin_user',
|
||||||
|
(string) $id,
|
||||||
|
$before,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
return ApiResponse::success(['deleted' => true, 'id' => $id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,8 @@ namespace App\Http\Controllers\Api\V1\Admin\User;
|
|||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Models\AdminUser;
|
use App\Models\AdminUser;
|
||||||
use App\Support\ApiResponse;
|
use App\Support\AdminApiList;
|
||||||
|
use App\Support\AdminUserApiPresenter;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
@@ -13,8 +14,7 @@ final class AdminUserIndexController extends Controller
|
|||||||
{
|
{
|
||||||
public function __invoke(Request $request): JsonResponse
|
public function __invoke(Request $request): JsonResponse
|
||||||
{
|
{
|
||||||
$perPage = min(max((int) $request->integer('per_page', 25), 1), 100);
|
$p = AdminApiList::readPaging($request);
|
||||||
$page = max((int) $request->integer('page', 1), 1);
|
|
||||||
$keyword = trim((string) $request->query('keyword', ''));
|
$keyword = trim((string) $request->query('keyword', ''));
|
||||||
|
|
||||||
$q = AdminUser::query()
|
$q = AdminUser::query()
|
||||||
@@ -29,33 +29,8 @@ final class AdminUserIndexController extends Controller
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$paginator = $q->paginate($perPage, ['*'], 'page', $page);
|
$paginator = $q->paginate($p['perPage'], ['*'], 'page', $p['page']);
|
||||||
|
|
||||||
return ApiResponse::success([
|
return AdminApiList::json($paginator, fn (AdminUser $user): array => AdminUserApiPresenter::listItem($user));
|
||||||
'items' => collect($paginator->items())->map(
|
|
||||||
fn (AdminUser $user): array => $this->row($user)
|
|
||||||
)->all(),
|
|
||||||
'meta' => [
|
|
||||||
'current_page' => $paginator->currentPage(),
|
|
||||||
'per_page' => $paginator->perPage(),
|
|
||||||
'total' => $paginator->total(),
|
|
||||||
'last_page' => $paginator->lastPage(),
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return array<string, mixed> */
|
|
||||||
private function row(AdminUser $user): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'id' => (int) $user->id,
|
|
||||||
'username' => $user->username,
|
|
||||||
'nickname' => $user->name,
|
|
||||||
'email' => $user->email,
|
|
||||||
'status' => (int) $user->status,
|
|
||||||
'roles' => $user->adminRoleSlugs(),
|
|
||||||
'direct_permissions' => $user->directLegacyPermissionSlugs(),
|
|
||||||
'effective_permissions' => $user->adminPermissionSlugs(),
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use App\Models\AdminUser;
|
|||||||
use App\Support\ApiResponse;
|
use App\Support\ApiResponse;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\DB;
|
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
/** PUT /api/v1/admin/admin-users/{admin_user}/roles */
|
/** PUT /api/v1/admin/admin-users/{admin_user}/roles */
|
||||||
@@ -22,29 +21,7 @@ final class AdminUserRoleSyncController extends Controller
|
|||||||
])->validate();
|
])->validate();
|
||||||
|
|
||||||
$slugs = array_values(array_unique($data['role_slugs']));
|
$slugs = array_values(array_unique($data['role_slugs']));
|
||||||
$siteId = AdminUser::defaultAdminSiteId();
|
$admin_user->syncRoleSlugsForDefaultSite($slugs);
|
||||||
|
|
||||||
$roleIds = DB::table('admin_roles')
|
|
||||||
->whereIn('slug', $slugs)
|
|
||||||
->pluck('id')
|
|
||||||
->all();
|
|
||||||
|
|
||||||
DB::transaction(function () use ($admin_user, $siteId, $roleIds): void {
|
|
||||||
DB::table('admin_user_site_roles')
|
|
||||||
->where('admin_user_id', $admin_user->id)
|
|
||||||
->where('site_id', $siteId)
|
|
||||||
->delete();
|
|
||||||
|
|
||||||
$now = now();
|
|
||||||
foreach ($roleIds as $rid) {
|
|
||||||
DB::table('admin_user_site_roles')->insert([
|
|
||||||
'admin_user_id' => $admin_user->id,
|
|
||||||
'site_id' => $siteId,
|
|
||||||
'role_id' => (int) $rid,
|
|
||||||
'granted_at' => $now,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$admin_user->load('roles');
|
$admin_user->load('roles');
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api\V1\Admin\User;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\AdminUser;
|
||||||
|
use App\Support\AdminUserApiPresenter;
|
||||||
|
use App\Support\ApiResponse;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
|
||||||
|
/** GET /api/v1/admin/admin-users/{admin_user} */
|
||||||
|
final class AdminUserShowController extends Controller
|
||||||
|
{
|
||||||
|
public function __invoke(AdminUser $admin_user): JsonResponse
|
||||||
|
{
|
||||||
|
$admin_user->load('roles');
|
||||||
|
|
||||||
|
return ApiResponse::success(AdminUserApiPresenter::listItem($admin_user));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api\V1\Admin\User;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\AdminUser;
|
||||||
|
use App\Services\AuditLogger;
|
||||||
|
use App\Support\AdminUserApiPresenter;
|
||||||
|
use App\Support\ApiResponse;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
/** POST /api/v1/admin/admin-users */
|
||||||
|
final class AdminUserStoreController extends Controller
|
||||||
|
{
|
||||||
|
public function __invoke(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
/** @var AdminUser $actor */
|
||||||
|
$actor = $request->lotteryAdmin();
|
||||||
|
|
||||||
|
$payload = $request->all();
|
||||||
|
if (isset($payload['username']) && is_string($payload['username'])) {
|
||||||
|
$payload['username'] = Str::lower(trim($payload['username']));
|
||||||
|
}
|
||||||
|
if (array_key_exists('email', $payload) && $payload['email'] === '') {
|
||||||
|
$payload['email'] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = validator($payload, [
|
||||||
|
'username' => ['required', 'string', 'min:2', 'max:64', 'regex:/^[a-zA-Z0-9._-]+$/u', 'unique:admin_users,username'],
|
||||||
|
'nickname' => ['required', 'string', 'max:128'],
|
||||||
|
'email' => ['nullable', 'string', 'email', 'max:255'],
|
||||||
|
'password' => ['required', 'string', 'min:8', 'max:256'],
|
||||||
|
'status' => ['sometimes', 'integer', 'in:0,1'],
|
||||||
|
'role_slugs' => ['required', 'array', 'min:1'],
|
||||||
|
'role_slugs.*' => ['string', 'max:64', 'distinct', 'exists:admin_roles,slug'],
|
||||||
|
])->validate();
|
||||||
|
|
||||||
|
$email = is_string($data['email'] ?? null) && trim($data['email']) !== ''
|
||||||
|
? trim($data['email'])
|
||||||
|
: null;
|
||||||
|
|
||||||
|
$roleSlugs = array_values(array_unique($data['role_slugs']));
|
||||||
|
|
||||||
|
$user = DB::transaction(function () use ($data, $email, $roleSlugs): AdminUser {
|
||||||
|
$created = AdminUser::query()->create([
|
||||||
|
'username' => $data['username'],
|
||||||
|
'name' => $data['nickname'],
|
||||||
|
'email' => $email,
|
||||||
|
'password' => $data['password'],
|
||||||
|
'status' => array_key_exists('status', $data) ? (int) $data['status'] : 0,
|
||||||
|
]);
|
||||||
|
$created->syncRoleSlugsForDefaultSite($roleSlugs);
|
||||||
|
|
||||||
|
return $created;
|
||||||
|
});
|
||||||
|
|
||||||
|
$user->load('roles');
|
||||||
|
|
||||||
|
AuditLogger::recordForAdmin(
|
||||||
|
$actor,
|
||||||
|
$request,
|
||||||
|
'system',
|
||||||
|
'admin_user.create',
|
||||||
|
'admin_user',
|
||||||
|
(string) $user->getKey(),
|
||||||
|
null,
|
||||||
|
AdminUserApiPresenter::listItem($user),
|
||||||
|
);
|
||||||
|
|
||||||
|
return ApiResponse::success(AdminUserApiPresenter::listItem($user));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api\V1\Admin\User;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\AdminUser;
|
||||||
|
use App\Services\AuditLogger;
|
||||||
|
use App\Support\AdminUserApiPresenter;
|
||||||
|
use App\Support\ApiResponse;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
/** PUT /api/v1/admin/admin-users/{admin_user} */
|
||||||
|
final class AdminUserUpdateController extends Controller
|
||||||
|
{
|
||||||
|
public function __invoke(Request $request, AdminUser $admin_user): JsonResponse
|
||||||
|
{
|
||||||
|
/** @var AdminUser $actor */
|
||||||
|
$actor = $request->lotteryAdmin();
|
||||||
|
|
||||||
|
$admin_user->load('roles');
|
||||||
|
$before = AdminUserApiPresenter::listItem($admin_user);
|
||||||
|
|
||||||
|
$payload = $request->all();
|
||||||
|
if (array_key_exists('email', $payload) && $payload['email'] === '') {
|
||||||
|
$payload['email'] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var array{nickname?:string,email?:?string,password?:?string,status?:int} $data */
|
||||||
|
$data = validator($payload, [
|
||||||
|
'nickname' => ['sometimes', 'string', 'max:128'],
|
||||||
|
'email' => ['sometimes', 'nullable', 'string', 'email', 'max:255', Rule::unique('admin_users', 'email')->ignore($admin_user->id)],
|
||||||
|
'password' => ['sometimes', 'nullable', 'string', 'min:8', 'max:256'],
|
||||||
|
'status' => ['sometimes', 'integer', Rule::in([0, 1])],
|
||||||
|
])->validate();
|
||||||
|
|
||||||
|
$updates = [];
|
||||||
|
if (array_key_exists('nickname', $data)) {
|
||||||
|
$updates['name'] = $data['nickname'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('email', $data)) {
|
||||||
|
$updates['email'] = ($data['email'] !== null && trim((string) $data['email']) !== '')
|
||||||
|
? trim((string) $data['email'])
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
if (array_key_exists('status', $data)) {
|
||||||
|
$updates['status'] = (int) $data['status'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('password', $data) && is_string($data['password']) && $data['password'] !== '') {
|
||||||
|
$updates['password'] = $data['password'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($updates === []) {
|
||||||
|
return ApiResponse::success($before);
|
||||||
|
}
|
||||||
|
|
||||||
|
$admin_user->fill($updates);
|
||||||
|
$admin_user->save();
|
||||||
|
$admin_user->load('roles');
|
||||||
|
|
||||||
|
$after = AdminUserApiPresenter::listItem($admin_user);
|
||||||
|
|
||||||
|
AuditLogger::recordForAdmin(
|
||||||
|
$actor,
|
||||||
|
$request,
|
||||||
|
'system',
|
||||||
|
'admin_user.update',
|
||||||
|
'admin_user',
|
||||||
|
(string) $admin_user->getKey(),
|
||||||
|
$before,
|
||||||
|
$after,
|
||||||
|
);
|
||||||
|
|
||||||
|
return ApiResponse::success($after);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -73,6 +73,38 @@ class AdminUser extends Authenticatable
|
|||||||
)->withPivot(['site_id', 'granted_at']);
|
)->withPivot(['site_id', 'granted_at']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将用户在默认站点上的角色设为指定 slug 集合(全量替换该站点 pivot)。
|
||||||
|
*
|
||||||
|
* @param list<string> $slugs
|
||||||
|
*/
|
||||||
|
public function syncRoleSlugsForDefaultSite(array $slugs): void
|
||||||
|
{
|
||||||
|
$siteId = self::defaultAdminSiteId();
|
||||||
|
$slugs = array_values(array_unique($slugs));
|
||||||
|
$roleIds = DB::table('admin_roles')
|
||||||
|
->whereIn('slug', $slugs)
|
||||||
|
->pluck('id')
|
||||||
|
->all();
|
||||||
|
|
||||||
|
DB::transaction(function () use ($siteId, $roleIds): void {
|
||||||
|
DB::table('admin_user_site_roles')
|
||||||
|
->where('admin_user_id', $this->id)
|
||||||
|
->where('site_id', $siteId)
|
||||||
|
->delete();
|
||||||
|
|
||||||
|
$now = now();
|
||||||
|
foreach ($roleIds as $rid) {
|
||||||
|
DB::table('admin_user_site_roles')->insert([
|
||||||
|
'admin_user_id' => $this->id,
|
||||||
|
'site_id' => $siteId,
|
||||||
|
'role_id' => (int) $rid,
|
||||||
|
'granted_at' => $now,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public function isSuperAdmin(): bool
|
public function isSuperAdmin(): bool
|
||||||
{
|
{
|
||||||
if ($this->relationLoaded('roles')) {
|
if ($this->relationLoaded('roles')) {
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ use Illuminate\Support\Facades\DB;
|
|||||||
final class OddsStreamService
|
final class OddsStreamService
|
||||||
{
|
{
|
||||||
/** @return LengthAwarePaginator<int, OddsVersion> */
|
/** @return LengthAwarePaginator<int, OddsVersion> */
|
||||||
public function paginate(?string $status, int $perPage): LengthAwarePaginator
|
public function paginate(?string $status, int $perPage, int $page = 1): LengthAwarePaginator
|
||||||
{
|
{
|
||||||
$q = OddsVersion::query()->orderByDesc('id');
|
$q = OddsVersion::query()->orderByDesc('id');
|
||||||
if ($status !== null && $status !== '') {
|
if ($status !== null && $status !== '') {
|
||||||
$q->where('status', $status);
|
$q->where('status', $status);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $q->paginate($perPage);
|
return $q->paginate($perPage, ['*'], 'page', max(1, $page));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createDraft(AdminUser $admin, ?string $reason, ?int $cloneFromVersionId): OddsVersion
|
public function createDraft(AdminUser $admin, ?string $reason, ?int $cloneFromVersionId): OddsVersion
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ use Illuminate\Support\Facades\DB;
|
|||||||
final class PlayConfigStreamService
|
final class PlayConfigStreamService
|
||||||
{
|
{
|
||||||
/** @return LengthAwarePaginator<int, PlayConfigVersion> */
|
/** @return LengthAwarePaginator<int, PlayConfigVersion> */
|
||||||
public function paginate(?string $status, int $perPage): LengthAwarePaginator
|
public function paginate(?string $status, int $perPage, int $page = 1): LengthAwarePaginator
|
||||||
{
|
{
|
||||||
$q = PlayConfigVersion::query()->orderByDesc('id');
|
$q = PlayConfigVersion::query()->orderByDesc('id');
|
||||||
if ($status !== null && $status !== '') {
|
if ($status !== null && $status !== '') {
|
||||||
$q->where('status', $status);
|
$q->where('status', $status);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $q->paginate($perPage);
|
return $q->paginate($perPage, ['*'], 'page', max(1, $page));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createDraft(AdminUser $admin, ?string $reason, ?int $cloneFromVersionId): PlayConfigVersion
|
public function createDraft(AdminUser $admin, ?string $reason, ?int $cloneFromVersionId): PlayConfigVersion
|
||||||
|
|||||||
@@ -15,14 +15,14 @@ use Illuminate\Support\Facades\DB;
|
|||||||
final class RiskCapStreamService
|
final class RiskCapStreamService
|
||||||
{
|
{
|
||||||
/** @return LengthAwarePaginator<int, RiskCapVersion> */
|
/** @return LengthAwarePaginator<int, RiskCapVersion> */
|
||||||
public function paginate(?string $status, int $perPage): LengthAwarePaginator
|
public function paginate(?string $status, int $perPage, int $page = 1): LengthAwarePaginator
|
||||||
{
|
{
|
||||||
$q = RiskCapVersion::query()->orderByDesc('id');
|
$q = RiskCapVersion::query()->orderByDesc('id');
|
||||||
if ($status !== null && $status !== '') {
|
if ($status !== null && $status !== '') {
|
||||||
$q->where('status', $status);
|
$q->where('status', $status);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $q->paginate($perPage);
|
return $q->paginate($perPage, ['*'], 'page', max(1, $page));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createDraft(AdminUser $admin, ?string $reason, ?int $cloneFromVersionId): RiskCapVersion
|
public function createDraft(AdminUser $admin, ?string $reason, ?int $cloneFromVersionId): RiskCapVersion
|
||||||
|
|||||||
75
app/Support/AdminApiList.php
Normal file
75
app/Support/AdminApiList.php
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Support;
|
||||||
|
|
||||||
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后台标准列表:`items` + `meta`(current_page / per_page / total / last_page)。
|
||||||
|
* 供各 Admin Index 控制器复用,避免重复拼装分页 JSON。
|
||||||
|
*/
|
||||||
|
final class AdminApiList
|
||||||
|
{
|
||||||
|
public const DEFAULT_PER_PAGE = 25;
|
||||||
|
|
||||||
|
public const MAX_PER_PAGE = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取 `page`、`per_page`,并夹在 [1, maxPerPage]。
|
||||||
|
*
|
||||||
|
* @return array{page: int, perPage: int}
|
||||||
|
*/
|
||||||
|
public static function readPaging(Request $request, int $defaultPerPage = self::DEFAULT_PER_PAGE, int $maxPerPage = self::MAX_PER_PAGE): array
|
||||||
|
{
|
||||||
|
$perPage = min(max((int) $request->integer('per_page', $defaultPerPage), 1), $maxPerPage);
|
||||||
|
$page = max((int) $request->integer('page', 1), 1);
|
||||||
|
|
||||||
|
return ['page' => $page, 'perPage' => $perPage];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param callable(object): array<string, mixed> $row
|
||||||
|
* @return array{items: list<array<string, mixed>>, meta: array{current_page: int, per_page: int, total: int, last_page: int}}
|
||||||
|
*/
|
||||||
|
public static function payload(LengthAwarePaginator $paginator, callable $row): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'items' => collect($paginator->items())->map($row)->values()->all(),
|
||||||
|
'meta' => self::meta($paginator),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array{current_page: int, per_page: int, total: int, last_page: int}
|
||||||
|
*/
|
||||||
|
public static function meta(LengthAwarePaginator $paginator): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'current_page' => $paginator->currentPage(),
|
||||||
|
'per_page' => $paginator->perPage(),
|
||||||
|
'total' => $paginator->total(),
|
||||||
|
'last_page' => $paginator->lastPage(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param callable(object): array<string, mixed> $row
|
||||||
|
*/
|
||||||
|
public static function json(LengthAwarePaginator $paginator, callable $row): JsonResponse
|
||||||
|
{
|
||||||
|
return ApiResponse::success(self::payload($paginator, $row));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在标准列表外包一层字段(如 draw_id、job_no),与 items、meta 同级合并。
|
||||||
|
*
|
||||||
|
* @param callable(object): array<string, mixed> $row
|
||||||
|
* @param array<string, mixed> $extra
|
||||||
|
*/
|
||||||
|
public static function jsonWith(LengthAwarePaginator $paginator, callable $row, array $extra = []): JsonResponse
|
||||||
|
{
|
||||||
|
return ApiResponse::success(array_merge($extra, self::payload($paginator, $row)));
|
||||||
|
}
|
||||||
|
}
|
||||||
26
app/Support/AdminUserApiPresenter.php
Normal file
26
app/Support/AdminUserApiPresenter.php
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Support;
|
||||||
|
|
||||||
|
use App\Models\AdminUser;
|
||||||
|
|
||||||
|
/** 管理员用户 API 中列表行 / 详情 / 变更成功后的统一 JSON 形状。 */
|
||||||
|
final class AdminUserApiPresenter
|
||||||
|
{
|
||||||
|
/** @return array<string, mixed> */
|
||||||
|
public static function listItem(AdminUser $user): array
|
||||||
|
{
|
||||||
|
$user->loadMissing('roles');
|
||||||
|
|
||||||
|
return [
|
||||||
|
'id' => (int) $user->id,
|
||||||
|
'username' => $user->username,
|
||||||
|
'nickname' => $user->name,
|
||||||
|
'email' => $user->email,
|
||||||
|
'status' => (int) $user->status,
|
||||||
|
'roles' => $user->adminRoleSlugs(),
|
||||||
|
'direct_permissions' => $user->directLegacyPermissionSlugs(),
|
||||||
|
'effective_permissions' => $user->adminPermissionSlugs(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,9 +48,13 @@ use App\Http\Controllers\Api\V1\Admin\Settlement\AdminSettlementBatchDetailsCont
|
|||||||
use App\Http\Controllers\Api\V1\Admin\Settlement\AdminSettlementBatchIndexController;
|
use App\Http\Controllers\Api\V1\Admin\Settlement\AdminSettlementBatchIndexController;
|
||||||
use App\Http\Controllers\Api\V1\Admin\Settlement\AdminSettlementBatchShowController;
|
use App\Http\Controllers\Api\V1\Admin\Settlement\AdminSettlementBatchShowController;
|
||||||
use App\Http\Controllers\Api\V1\Admin\User\AdminPermissionCatalogController;
|
use App\Http\Controllers\Api\V1\Admin\User\AdminPermissionCatalogController;
|
||||||
|
use App\Http\Controllers\Api\V1\Admin\User\AdminUserDestroyController;
|
||||||
use App\Http\Controllers\Api\V1\Admin\User\AdminUserIndexController;
|
use App\Http\Controllers\Api\V1\Admin\User\AdminUserIndexController;
|
||||||
use App\Http\Controllers\Api\V1\Admin\User\AdminUserPermissionSyncController;
|
use App\Http\Controllers\Api\V1\Admin\User\AdminUserPermissionSyncController;
|
||||||
use App\Http\Controllers\Api\V1\Admin\User\AdminUserRoleSyncController;
|
use App\Http\Controllers\Api\V1\Admin\User\AdminUserRoleSyncController;
|
||||||
|
use App\Http\Controllers\Api\V1\Admin\User\AdminUserShowController;
|
||||||
|
use App\Http\Controllers\Api\V1\Admin\User\AdminUserStoreController;
|
||||||
|
use App\Http\Controllers\Api\V1\Admin\User\AdminUserUpdateController;
|
||||||
use App\Http\Controllers\Api\V1\Admin\Wallet\TransferOrderListController;
|
use App\Http\Controllers\Api\V1\Admin\Wallet\TransferOrderListController;
|
||||||
use App\Http\Controllers\Api\V1\Admin\Wallet\WalletTransactionListController;
|
use App\Http\Controllers\Api\V1\Admin\Wallet\WalletTransactionListController;
|
||||||
use App\Http\Controllers\Api\V1\Draw\DrawCurrentController;
|
use App\Http\Controllers\Api\V1\Draw\DrawCurrentController;
|
||||||
@@ -315,6 +319,10 @@ Route::prefix('v1')->group(function (): void {
|
|||||||
/** 后台账号与权限分配:仅可管理账户执行。 */
|
/** 后台账号与权限分配:仅可管理账户执行。 */
|
||||||
Route::middleware('admin.permission:prd.admin_user.manage')->group(function (): void {
|
Route::middleware('admin.permission:prd.admin_user.manage')->group(function (): void {
|
||||||
Route::get('admin-users', AdminUserIndexController::class)->name('admin-users.index');
|
Route::get('admin-users', AdminUserIndexController::class)->name('admin-users.index');
|
||||||
|
Route::post('admin-users', AdminUserStoreController::class)->name('admin-users.store');
|
||||||
|
Route::get('admin-users/{admin_user}', AdminUserShowController::class)->name('admin-users.show');
|
||||||
|
Route::put('admin-users/{admin_user}', AdminUserUpdateController::class)->name('admin-users.update');
|
||||||
|
Route::delete('admin-users/{admin_user}', AdminUserDestroyController::class)->name('admin-users.destroy');
|
||||||
Route::get('admin-user-permission-catalog', AdminPermissionCatalogController::class)
|
Route::get('admin-user-permission-catalog', AdminPermissionCatalogController::class)
|
||||||
->name('admin-users.permission-catalog');
|
->name('admin-users.permission-catalog');
|
||||||
Route::put('admin-users/{admin_user}/permissions', AdminUserPermissionSyncController::class)
|
Route::put('admin-users/{admin_user}/permissions', AdminUserPermissionSyncController::class)
|
||||||
|
|||||||
@@ -153,3 +153,127 @@ test('admin can sync user roles for default site', function (): void {
|
|||||||
sort($slugs);
|
sort($slugs);
|
||||||
expect($slugs)->toBe(['role_sync_a', 'role_sync_b']);
|
expect($slugs)->toBe(['role_sync_a', 'role_sync_b']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('admin can create update and delete users with crud rules', function (): void {
|
||||||
|
$token = makeAdminWithPermissions('crud_actor', ['prd.admin_user.manage']);
|
||||||
|
|
||||||
|
$crudRole = AdminRole::query()->create(['slug' => 'crud_new_user_role', 'name' => 'Crud Role']);
|
||||||
|
|
||||||
|
$this->withHeader('Authorization', 'Bearer '.$token)
|
||||||
|
->postJson('/api/v1/admin/admin-users', [
|
||||||
|
'username' => 'NewUser_XX',
|
||||||
|
'nickname' => '新用户',
|
||||||
|
'email' => 'newuser@example.com',
|
||||||
|
'password' => 'secret-long',
|
||||||
|
'status' => 0,
|
||||||
|
'role_slugs' => ['crud_new_user_role'],
|
||||||
|
])
|
||||||
|
->assertOk()
|
||||||
|
->assertJsonPath('code', ErrorCode::Success->value)
|
||||||
|
->assertJsonPath('data.username', 'newuser_xx')
|
||||||
|
->assertJsonPath('data.roles.0', 'crud_new_user_role');
|
||||||
|
|
||||||
|
$created = AdminUser::query()->where('username', 'newuser_xx')->firstOrFail();
|
||||||
|
expect($created->adminRoleSlugs())->toContain('crud_new_user_role');
|
||||||
|
|
||||||
|
$this->withHeader('Authorization', 'Bearer '.$token)
|
||||||
|
->postJson('/api/v1/admin/admin-users', [
|
||||||
|
'username' => 'newuser_xx',
|
||||||
|
'nickname' => 'dup',
|
||||||
|
'email' => null,
|
||||||
|
'password' => 'secret-long',
|
||||||
|
'role_slugs' => [$crudRole->slug],
|
||||||
|
])
|
||||||
|
->assertStatus(422)
|
||||||
|
->assertJsonPath('code', ErrorCode::ValidationFailed->value);
|
||||||
|
|
||||||
|
$target = AdminUser::query()->where('username', 'newuser_xx')->firstOrFail();
|
||||||
|
$this->withHeader('Authorization', 'Bearer '.$token)
|
||||||
|
->putJson('/api/v1/admin/admin-users/'.$target->id, [
|
||||||
|
'nickname' => '已改名',
|
||||||
|
'email' => null,
|
||||||
|
'password' => 'new-secret-9',
|
||||||
|
])
|
||||||
|
->assertOk()
|
||||||
|
->assertJsonPath('data.nickname', '已改名');
|
||||||
|
|
||||||
|
expect(Hash::check('new-secret-9', $target->fresh()->password))->toBeTrue();
|
||||||
|
|
||||||
|
$victim = AdminUser::query()->create([
|
||||||
|
'username' => 'to_delete',
|
||||||
|
'name' => 'Delete Me',
|
||||||
|
'email' => null,
|
||||||
|
'password' => Hash::make('secret-strong'),
|
||||||
|
'status' => 0,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->withHeader('Authorization', 'Bearer '.$token)
|
||||||
|
->deleteJson('/api/v1/admin/admin-users/'.$victim->id)
|
||||||
|
->assertOk()
|
||||||
|
->assertJsonPath('data.deleted', true);
|
||||||
|
|
||||||
|
expect(AdminUser::query()->whereKey($victim->id)->exists())->toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('admin user create requires at least one role slug', function (): void {
|
||||||
|
$token = makeAdminWithPermissions('create_need_roles', ['prd.admin_user.manage']);
|
||||||
|
AdminRole::query()->create(['slug' => 'role_for_create_gate', 'name' => 'Gate Role']);
|
||||||
|
|
||||||
|
$this->withHeader('Authorization', 'Bearer '.$token)
|
||||||
|
->postJson('/api/v1/admin/admin-users', [
|
||||||
|
'username' => 'no_roles_user',
|
||||||
|
'nickname' => 'NR',
|
||||||
|
'email' => null,
|
||||||
|
'password' => 'secret-long',
|
||||||
|
'role_slugs' => [],
|
||||||
|
])
|
||||||
|
->assertStatus(422)
|
||||||
|
->assertJsonPath('code', ErrorCode::ValidationFailed->value);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('admin cannot delete self', function (): void {
|
||||||
|
$token = makeAdminWithPermissions('self_guard', ['prd.admin_user.manage']);
|
||||||
|
$me = AdminUser::query()->where('username', 'self_guard')->firstOrFail();
|
||||||
|
|
||||||
|
$this->withHeader('Authorization', 'Bearer '.$token)
|
||||||
|
->deleteJson('/api/v1/admin/admin-users/'.$me->id)
|
||||||
|
->assertStatus(422)
|
||||||
|
->assertJsonPath('code', ErrorCode::ValidationFailed->value)
|
||||||
|
->assertJsonPath('msg', '不能删除当前登录账号');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('admin cannot delete the last super admin', function (): void {
|
||||||
|
$token = makeAdminWithPermissions('super_deleter', ['prd.admin_user.manage']);
|
||||||
|
|
||||||
|
$s1 = AdminUser::query()->create([
|
||||||
|
'username' => 'super_one',
|
||||||
|
'name' => 'S1',
|
||||||
|
'email' => null,
|
||||||
|
'password' => Hash::make('secret-strong'),
|
||||||
|
'status' => 0,
|
||||||
|
]);
|
||||||
|
grantSuperAdminRole($s1);
|
||||||
|
|
||||||
|
$this->withHeader('Authorization', 'Bearer '.$token)
|
||||||
|
->deleteJson('/api/v1/admin/admin-users/'.$s1->id)
|
||||||
|
->assertStatus(422)
|
||||||
|
->assertJsonPath('msg', '不能删除最后一个超级管理员');
|
||||||
|
|
||||||
|
$s2 = AdminUser::query()->create([
|
||||||
|
'username' => 'super_two',
|
||||||
|
'name' => 'S2',
|
||||||
|
'email' => null,
|
||||||
|
'password' => Hash::make('secret-strong'),
|
||||||
|
'status' => 0,
|
||||||
|
]);
|
||||||
|
grantSuperAdminRole($s2);
|
||||||
|
|
||||||
|
$this->withHeader('Authorization', 'Bearer '.$token)
|
||||||
|
->deleteJson('/api/v1/admin/admin-users/'.$s1->id)
|
||||||
|
->assertOk();
|
||||||
|
|
||||||
|
$this->withHeader('Authorization', 'Bearer '.$token)
|
||||||
|
->deleteJson('/api/v1/admin/admin-users/'.$s2->id)
|
||||||
|
->assertStatus(422)
|
||||||
|
->assertJsonPath('msg', '不能删除最后一个超级管理员');
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user