diff --git a/api/app/Http/Controllers/GameController.php b/api/app/Http/Controllers/GameController.php index bde41ba..057306e 100644 --- a/api/app/Http/Controllers/GameController.php +++ b/api/app/Http/Controllers/GameController.php @@ -17,15 +17,12 @@ class GameController extends Controller $user = Auth::user(); $query = Game::query()->with(["winner", "player1", "player2"]); - // Filter games based on user type if ($user->type !== 'A') { - // Players can only see games they participate in $query->where(function ($q) use ($user) { $q->where('player1_user_id', $user->id) ->orWhere('player2_user_id', $user->id); }); } - // Admins see all games (no filter needed) if ($request->has("type") && in_array($request->type, ["3", "9"])) { $query->where("type", $request->type); diff --git a/api/app/Http/Controllers/TransactionController.php b/api/app/Http/Controllers/TransactionController.php new file mode 100644 index 0000000..41b62c8 --- /dev/null +++ b/api/app/Http/Controllers/TransactionController.php @@ -0,0 +1,31 @@ +authorize('viewAny', CoinTransaction::class); + + $query = CoinTransaction::with('user:id,nickname,email', 'type:id,name'); + + if ($request->has('sort_coins')) { + $direction = $request->get('sort_coins') === 'asc' ? 'asc' : 'desc'; + $query->orderBy('coins', $direction); + } + + $dateDirection = $request->get('sort_datetime') === 'asc' ? 'asc' : 'desc'; + $query->orderBy('transaction_datetime', $dateDirection); + + + $transactions = $query->paginate(15); + + return response()->json($transactions); + } +} \ No newline at end of file diff --git a/api/app/Http/Controllers/UserController.php b/api/app/Http/Controllers/UserController.php index 2fa423c..98a063d 100644 --- a/api/app/Http/Controllers/UserController.php +++ b/api/app/Http/Controllers/UserController.php @@ -21,11 +21,14 @@ class UserController extends Controller $query = User::query(); - // Filtros úteis para o Backoffice if ($request->has('type')) { $query->where('type', $request->type); } + if ($request->has('blocked')) { + $query->where('blocked', $request->type); + } + if ($request->has('search')) { $query->where(function ($q) use ($request) { $q->where('name', 'like', '%'.$request->search.'%') @@ -47,7 +50,6 @@ class UserController extends Controller $validated = $request->validate([ 'name' => 'required|string|max:255', - 'nickname' => 'required|string|max:20|unique:users,nickname', 'email' => 'required|email|unique:users,email', 'password' => 'required|string|min:3', 'type' => 'required|in:A,U', diff --git a/api/app/Policies/CoinTransactionPolicy.php b/api/app/Policies/CoinTransactionPolicy.php new file mode 100644 index 0000000..6b3ce71 --- /dev/null +++ b/api/app/Policies/CoinTransactionPolicy.php @@ -0,0 +1,18 @@ +type === 'A' ? true : false; + } +} diff --git a/api/app/Policies/GamePolicy.php b/api/app/Policies/GamePolicy.php index 157f98c..7345bfb 100644 --- a/api/app/Policies/GamePolicy.php +++ b/api/app/Policies/GamePolicy.php @@ -20,7 +20,7 @@ class GamePolicy */ public function view(User $user, Game $game): bool { - if ($user->type === 'A') { + if ($user->type === "A") { return true; } @@ -31,6 +31,10 @@ class GamePolicy return true; } + if ($game->status === "Pending") { + return true; + } + return false; } @@ -39,7 +43,7 @@ class GamePolicy */ public function create(User $user): bool { - if ($user->type === 'A') { + if ($user->type === "A") { return false; } @@ -48,28 +52,32 @@ class GamePolicy public function join(User $user, Game $game): bool { - if ($user->type === 'A') { + if ($user->type === "A") { return false; } if ( - $game->status !== 'waiting' || + $game->status !== "Pending" || $game->player1_user_id === $user->id ) { return false; } + if ($game->player2_user_id !== null && $game->player2_user_id !== 1) { + return false; + } + return true; } public function resign(User $user, Game $game): bool { - if ($user->type === 'A') { + if ($user->type === "A") { return false; } if ( - $game->status !== 'ongoing' || + $game->status !== "Playing" || ($game->player1_user_id !== $user->id && $game->player2_user_id !== $user->id) ) { @@ -84,12 +92,12 @@ class GamePolicy */ public function update(User $user, Game $game): bool { - if ($user->type === 'A') { + if ($user->type === "A") { return false; } if ( - $game->status !== 'ongoing' || + $game->status !== "Playing" || ($game->player1_user_id !== $user->id && $game->player2_user_id !== $user->id) ) { @@ -105,7 +113,7 @@ class GamePolicy public function delete(User $user, Game $game): bool { // Only admins can delete games - return $user->type === 'A'; + return $user->type === "A"; } /** diff --git a/api/routes/api.php b/api/routes/api.php index cc96ded..1809c01 100644 --- a/api/routes/api.php +++ b/api/routes/api.php @@ -7,6 +7,7 @@ use App\Http\Controllers\ProfileController; use App\Http\Controllers\StatisticsController; use App\Http\Controllers\UserController; use App\Http\Controllers\CoinPurchaseController; +use App\Http\Controllers\TransactionController; use Illuminate\Support\Facades\Route; Route::prefix('v1')->group(function () { @@ -97,6 +98,7 @@ Route::prefix('v1')->group(function () { ->prefix('admin') ->group(function () { Route::get('/statistics', [StatisticsController::class, 'getAdminStats']); + Route::get('/transactions', [TransactionController::class, 'index']); Route::prefix('users')->group(function () { Route::get('/', [UserController::class, 'index']); Route::post('/', [UserController::class, 'store']); diff --git a/api/sample-requests.http b/api/sample-requests.http index 1172b90..4311fae 100644 --- a/api/sample-requests.http +++ b/api/sample-requests.http @@ -5,7 +5,7 @@ Content-Type: application/json Accept: application/json { - "email": "pa@mail.pt", + "email": "a1@mail.pt", "password": "123" } @@ -14,7 +14,7 @@ Accept: application/json @id = {{login.response.body.user.id}} ### Get All matches -GET http://localhost:8000/api/v1/matches +GET http://localhost:8000/api/v1/games Content-Type: application/json Accept: application/json Authorization: Bearer {{token}} @@ -55,7 +55,7 @@ Authorization: Bearer {{token}} "payment_reference": "912345678" } -### Get public stats +### Get leaderboard GET http://localhost:8000/api/v1/leaderboard Content-Type: application/json Accept: application/json @@ -64,4 +64,21 @@ Accept: application/json GET http://localhost:8000/api/v1/statistics/me Content-Type: application/json Accept: application/json +Authorization: Bearer {{token}} + +### Get public stats +GET http://localhost:8000/api/v1/statistics/public +Content-Type: application/json +Accept: application/json + +### Get admin stats +GET http://localhost:8000/api/v1/admin/statistics +Content-Type: application/json +Accept: application/json +Authorization: Bearer {{token}} + +### Get admin stats +GET http://localhost:8000/api/v1/admin/users +Content-Type: application/json +Accept: application/json Authorization: Bearer {{token}} \ No newline at end of file diff --git a/bruno_collection/Games/Create Game.bru b/bruno_collection/Games/Create Game.bru new file mode 100644 index 0000000..d027b66 --- /dev/null +++ b/bruno_collection/Games/Create Game.bru @@ -0,0 +1,15 @@ +meta { + name: Create Game + type: http + seq: 3 +} + +post { + url: {{api_url}}/games + body: none + auth: inherit +} + +settings { + encodeUrl: true +} diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 8450f33..da16d8c 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -3,8 +3,7 @@