Merge branch 'develop' into feature/api-stats

This commit is contained in:
2025-12-29 19:07:38 +00:00
9 changed files with 325 additions and 49 deletions
+11 -4
View File
@@ -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([
@@ -57,8 +64,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,
]);
@@ -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(),
]);
}
}
+50 -37
View File
@@ -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) {
@@ -184,4 +174,27 @@ class UserController extends Controller
return response()->json($matches);
}
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();
return response()->json(['message' => 'User unblocked successfully']);
}
}
+126
View File
@@ -0,0 +1,126 @@
<?php
namespace App\Policies;
use App\Models\Game;
use App\Models\User;
class GamePolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return true;
}
/**2
* Determine whether the user can view the model.
*/
public function view(User $user, Game $game): bool
{
if ($user->type === 'A') {
return true;
}
if (
$game->player1_user_id === $user->id ||
$game->player2_user_id === $user->id
) {
return true;
}
return false;
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
if ($user->type === 'A') {
return false;
}
return true;
}
public function join(User $user, Game $game): bool
{
if ($user->type === 'A') {
return false;
}
if (
$game->status !== 'waiting' ||
$game->player1_user_id === $user->id
) {
return false;
}
return true;
}
public function resign(User $user, Game $game): bool
{
if ($user->type === 'A') {
return false;
}
if (
$game->status !== 'ongoing' ||
($game->player1_user_id !== $user->id &&
$game->player2_user_id !== $user->id)
) {
return false;
}
return true;
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, Game $game): bool
{
if ($user->type === 'A') {
return false;
}
if (
$game->status !== 'ongoing' ||
($game->player1_user_id !== $user->id &&
$game->player2_user_id !== $user->id)
) {
return false;
}
return true;
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, Game $game): bool
{
// Only admins can delete games
return $user->type === 'A';
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, Game $game): bool
{
return false;
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, Game $game): bool
{
return false;
}
}
+74
View File
@@ -0,0 +1,74 @@
<?php
namespace App\Policies;
use App\Models\User;
class UserPolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return $user->type === 'A';
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, User $model): bool
{
return $user->id === $model->id || $user->type === 'A';
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return $user->type === 'A';
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, User $model): bool
{
return $user->id === $model->id;
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, User $model): bool
{
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';
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, User $model): bool
{
return false;
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, User $model): bool
{
return false;
}
}