diff --git a/api/app/Http/Controllers/AuthController.php b/api/app/Http/Controllers/AuthController.php index f60cabd..afd66e9 100644 --- a/api/app/Http/Controllers/AuthController.php +++ b/api/app/Http/Controllers/AuthController.php @@ -2,11 +2,11 @@ namespace App\Http\Controllers; +use App\Http\Requests\RegisterRequest; +use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Validation\ValidationException; -use App\Models\User; -use App\Http\Requests\RegisterRequest; class AuthController extends Controller { @@ -24,6 +24,13 @@ class AuthController extends Controller } $user = Auth::user(); + + if ($user->blocked) { + Auth::logout(); + + return response()->json(['message' => 'Your account is blocked. Please contact support.'], 403); + } + $token = $user->createToken('auth-token')->plainTextToken; return response()->json([ @@ -53,8 +60,8 @@ class AuthController extends Controller 'name' => $request->name, 'password' => bcrypt($request->password), 'photo_avatar_filename' => $request->photo, - 'type' => 'P', - 'blocked' => false, + 'type' => 'P', + 'blocked' => false, 'coins_balance' => 10, ]); diff --git a/api/app/Http/Controllers/GameController.php b/api/app/Http/Controllers/GameController.php index 1a245fc..886243e 100644 --- a/api/app/Http/Controllers/GameController.php +++ b/api/app/Http/Controllers/GameController.php @@ -14,7 +14,20 @@ class GameController extends Controller public function index(Request $request) { + $this->authorize('viewAny', Game::class); + + $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); @@ -43,6 +56,8 @@ class GameController extends Controller public function store(Request $request) { + $this->authorize('create', Game::class); + $validated = $request->validate([ "type" => "required|in:3,9", ]); @@ -81,6 +96,8 @@ class GameController extends Controller public function join(Game $game) { + $this->authorize('join', $game); + $user = Auth::user(); if ($game->player1_user_id == $user->id) { @@ -107,12 +124,16 @@ class GameController extends Controller public function show(Game $game) { + $this->authorize('view', $game); + $game->load(["player1", "player2", "winner"]); return response()->json($game); } public function update(Request $request, Game $game) { + $this->authorize('update', $game); + if ($game->status == "Ended") { return response()->json(["message" => "Game already ended"], 400); } @@ -135,4 +156,25 @@ class GameController extends Controller return response()->json($game); } + + public function resign(Game $game) + { + $this->authorize('resign', $game); + + $user = Auth::user(); + + $game->update([ + 'status' => 'Ended', + 'winner_user_id' => $game->player1_user_id === $user->id + ? $game->player2_user_id + : $game->player1_user_id, + 'loser_user_id' => $user->id, + 'ended_at' => now(), + ]); + + return response()->json([ + 'message' => 'You have resigned from the game', + 'game' => $game->fresh(), + ]); + } } diff --git a/api/app/Http/Controllers/UserController.php b/api/app/Http/Controllers/UserController.php index 5583071..7825179 100644 --- a/api/app/Http/Controllers/UserController.php +++ b/api/app/Http/Controllers/UserController.php @@ -17,6 +17,8 @@ class UserController extends Controller */ public function index(Request $request) { + $this->authorize('viewAny', User::class); + $query = User::query(); // Filtros úteis para o Backoffice @@ -41,6 +43,8 @@ class UserController extends Controller */ public function store(Request $request) { + $this->authorize('create', User::class); + $validated = $request->validate([ 'name' => 'required|string|max:255', 'nickname' => 'required|string|max:20|unique:users,nickname', @@ -73,7 +77,11 @@ class UserController extends Controller public function show(User $user) { $currentUser = Auth::user(); - if ($currentUser->id !== $user->id && $currentUser->type !== 'A') { + + // Admins and owners get full profile, others get limited view + if ($currentUser->type === 'A' || $currentUser->id === $user->id) { + return response()->json($user); + } else { return response()->json([ 'id' => $user->id, 'name' => $user->name, @@ -82,8 +90,6 @@ class UserController extends Controller 'type' => $user->type, ]); } - - return response()->json($user); } /** @@ -92,12 +98,8 @@ class UserController extends Controller */ public function update(Request $request, User $user) { - $currentUser = Auth::user(); - - if ($currentUser->id !== $user->id && $currentUser->type !== 'A') { - return response()->json(['message' => 'Unauthorized'], 403); - } - + $this->authorize('update', $user); + $validated = $request->validate([ 'name' => 'sometimes|string|max:255', 'nickname' => [ @@ -112,16 +114,8 @@ class UserController extends Controller Rule::unique('users')->ignore($user->id), ], 'password' => 'sometimes|string|min:3', - 'blocked' => 'sometimes|boolean', ]); - if (isset($validated['blocked']) && $currentUser->type !== 'A') { - return response()->json( - ['message' => 'Only admins can block users'], - 403, - ); - } - // Lógica de Upload de Foto (Exemplo Básico) // if ($request->hasFile('photo_avatar')) { // $path = $request->file('photo_avatar')->store('avatars', 'public'); @@ -139,24 +133,24 @@ class UserController extends Controller */ public function destroy(User $user) { - $currentUser = Auth::user(); + $this->authorize('delete', $user); - if ($currentUser->id !== $user->id && $currentUser->type !== 'A') { - return response()->json(['message' => 'Unauthorized'], 403); + // Check if user has transactions or games - if so, soft delete + $hasTransactions = $user->transactions()->exists(); + $hasGames = Game::where(function ($q) use ($user) { + $q->where('player1_user_id', $user->id) + ->orWhere('player2_user_id', $user->id); + })->exists(); + + if ($hasTransactions || $hasGames) { + $user->delete(); // Soft delete + $message = 'User account deactivated (soft-deleted due to transaction/game history)'; + } else { + $user->forceDelete(); // Hard delete + $message = 'User permanently deleted'; } - if ($currentUser->id === $user->id && $currentUser->type === 'A') { - if ($user->type === 'A') { - return response()->json( - ['message' => 'Admins cannot delete their own account'], - 403, - ); - } - } - - $user->delete(); - - return response()->json(['message' => 'User deleted successfully']); + return response()->json(['message' => $message]); } /** @@ -165,11 +159,7 @@ class UserController extends Controller */ public function getMatches(Request $request, User $user) { - $currentUser = Auth::user(); - - if ($currentUser->id !== $user->id && $currentUser->type !== 'A') { - return response()->json(['message' => 'Unauthorized'], 403); - } + $this->authorize('view', $user); $matches = Game::query() ->where(function ($q) use ($user) { @@ -187,14 +177,21 @@ class UserController extends Controller public function block(User $user) { + $this->authorize('block', $user); + $user->blocked = true; $user->save(); + // Revoke all active tokens for immediate effect + $user->tokens()->delete(); + return response()->json(['message' => 'User blocked successfully']); } public function unblock(User $user) { + $this->authorize('unblock', $user); + $user->blocked = false; $user->save(); diff --git a/api/app/Policies/GamePolicy.php b/api/app/Policies/GamePolicy.php index 7be2082..157f98c 100644 --- a/api/app/Policies/GamePolicy.php +++ b/api/app/Policies/GamePolicy.php @@ -12,9 +12,6 @@ class GamePolicy */ public function viewAny(User $user): bool { - if ($user->blocked === 1) { - return false; - } return true; } @@ -23,12 +20,9 @@ class GamePolicy */ public function view(User $user, Game $game): bool { - if ($user->type === "A") { + if ($user->type === 'A') { return true; } - if ($user->blocked === 1) { - return false; - } if ( $game->player1_user_id === $user->id || @@ -45,7 +39,7 @@ class GamePolicy */ public function create(User $user): bool { - if ($user->type === "A" || $user->blocked === 1) { + if ($user->type === 'A') { return false; } @@ -54,12 +48,12 @@ class GamePolicy public function join(User $user, Game $game): bool { - if ($user->type === "A" || $user->blocked === 1) { + if ($user->type === 'A') { return false; } if ( - $game->status !== "waiting" || + $game->status !== 'waiting' || $game->player1_user_id === $user->id ) { return false; @@ -70,12 +64,12 @@ class GamePolicy public function resign(User $user, Game $game): bool { - if ($user->type === "A" || $user->blocked === 1) { + if ($user->type === 'A') { return false; } if ( - $game->status !== "ongoing" || + $game->status !== 'ongoing' || ($game->player1_user_id !== $user->id && $game->player2_user_id !== $user->id) ) { @@ -90,12 +84,12 @@ class GamePolicy */ public function update(User $user, Game $game): bool { - if ($user->type === "A" || $user->blocked === 1) { + if ($user->type === 'A') { return false; } if ( - $game->status !== "ongoing" || + $game->status !== 'ongoing' || ($game->player1_user_id !== $user->id && $game->player2_user_id !== $user->id) ) { @@ -110,7 +104,8 @@ class GamePolicy */ public function delete(User $user, Game $game): bool { - return false; + // Only admins can delete games + return $user->type === 'A'; } /** diff --git a/api/app/Policies/UserPolicy.php b/api/app/Policies/UserPolicy.php index 74c0f07..548f1c7 100644 --- a/api/app/Policies/UserPolicy.php +++ b/api/app/Policies/UserPolicy.php @@ -3,7 +3,6 @@ namespace App\Policies; use App\Models\User; -use Illuminate\Auth\Access\Response; class UserPolicy { @@ -12,7 +11,7 @@ class UserPolicy */ public function viewAny(User $user): bool { - return false; + return $user->type === 'A'; } /** @@ -20,7 +19,7 @@ class UserPolicy */ public function view(User $user, User $model): bool { - return false; + return $user->id === $model->id || $user->type === 'A'; } /** @@ -28,7 +27,7 @@ class UserPolicy */ public function create(User $user): bool { - return false; + return $user->type === 'A'; } /** @@ -36,7 +35,7 @@ class UserPolicy */ public function update(User $user, User $model): bool { - return false; + return $user->id === $model->id; } /** @@ -44,7 +43,17 @@ class UserPolicy */ public function delete(User $user, User $model): bool { - return false; + return ($user->type === 'A' && $user->id !== $model->id) || ($user->type === 'P' && $user->id === $model->id); + } + + public function block(User $user, User $model): bool + { + return $user->type === 'A' && $user->id !== $model->id && $model->type === 'P'; + } + + public function unblock(User $user, User $model): bool + { + return $user->type === 'A' && $user->id !== $model->id && $model->type === 'P'; } /** diff --git a/websockets/.env b/websockets/.env new file mode 100644 index 0000000..e3eb3f7 --- /dev/null +++ b/websockets/.env @@ -0,0 +1,2 @@ +PORT=3000 +API_URL=http://localhost:8000/api \ No newline at end of file