diff --git a/api/app/Http/Controllers/StatisticsController.php b/api/app/Http/Controllers/StatisticsController.php index faf7d6e..d0d529b 100644 --- a/api/app/Http/Controllers/StatisticsController.php +++ b/api/app/Http/Controllers/StatisticsController.php @@ -7,6 +7,7 @@ use App\Models\Game; use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; +use App\Models\CoinTransaction; class StatisticsController extends Controller { @@ -73,4 +74,56 @@ class StatisticsController extends Controller 'current_balance' => $user->coins_balance, // Extra info ]); } + + public function getAdminStats() + { + $totalPlayers = User::where('type', 'P')->count(); + $totalGames = Game::count(); + $totalBlockedUsers = User::where('blocked', true)->count(); + + $gamesByType = Game::select('type', DB::raw('count(*) as total')) + ->groupBy('type') + ->get(); + + + $gamesPerMonth = Game::select( + DB::raw("strftime('%Y-%m', began_at) as month"), + DB::raw('count(*) as total') + ) + ->whereNotNull('began_at') + ->groupBy('month') + ->orderBy('month', 'desc') + ->limit(12) + ->get(); + + $totalCoinsPurchased = \App\Models\CoinTransaction::whereHas('type', function($q) { + $q->where('name', 'Coin purchase'); + }) + ->sum('coins'); + + $purchasesPerMonth = \App\Models\CoinTransaction::join('coin_transaction_types', 'coin_transactions.coin_transaction_type_id', '=', 'coin_transaction_types.id') + ->where('coin_transaction_types.name', 'Coin purchase') + ->select( + DB::raw("strftime('%Y-%m', coin_transactions.transaction_datetime) as month"), + DB::raw('SUM(coin_transactions.coins) as total_coins') + ) + ->groupBy('month') + ->orderBy('month', 'desc') + ->limit(12) + ->get(); + + return response()->json([ + 'global_counters' => [ + 'total_players' => $totalPlayers, + 'total_games' => $totalGames, + 'blocked_users' => $totalBlockedUsers, + 'total_coins_purchased' => (int) $totalCoinsPurchased, + ], + 'charts' => [ + 'games_by_type' => $gamesByType, + 'games_per_month' => $gamesPerMonth, + 'purchases_per_month' => $purchasesPerMonth, + ] + ]); + } } \ No newline at end of file diff --git a/api/app/Http/Controllers/UserController.php b/api/app/Http/Controllers/UserController.php index 46f6490..675d0d3 100644 --- a/api/app/Http/Controllers/UserController.php +++ b/api/app/Http/Controllers/UserController.php @@ -219,4 +219,37 @@ class UserController extends Controller return response()->json(['message' => 'User unblocked successfully']); } + + public function getTransactions(Request $request, User $user) + { + if ($request->user()->id !== $user->id && $request->user()->type !== 'A') { + return response()->json(['message' => 'Forbidden'], 403); + } + + $query = $user->transactions()->with('type'); + + if ($request->has('type')) { + $query->whereHas('type', function ($q) use ($request) { + $q->where('name', $request->type); + }); + } + + if ($request->has('date_from')) { + $query->whereDate('transaction_datetime', '>=', $request->date_from); + } + + if ($request->has('date_to')) { + $query->whereDate('transaction_datetime', '<=', $request->date_to); + } + + $transactions = $query->orderBy('transaction_datetime', 'desc') + ->paginate(10); + + return response()->json($transactions); + } + + public function getMyTransactions(Request $request) + { + return $this->getTransactions($request, $request->user()); + } } diff --git a/api/app/Models/CoinTransaction.php b/api/app/Models/CoinTransaction.php new file mode 100644 index 0000000..024c9eb --- /dev/null +++ b/api/app/Models/CoinTransaction.php @@ -0,0 +1,40 @@ + 'datetime', + 'custom' => 'array', + ]; + + public function type() + { + return $this->belongsTo(CoinTransactionType::class, 'coin_transaction_type_id'); + } + + public function user() + { + return $this->belongsTo(User::class); + } +} \ No newline at end of file diff --git a/api/app/Models/CoinTransactionType.php b/api/app/Models/CoinTransactionType.php new file mode 100644 index 0000000..6caca4b --- /dev/null +++ b/api/app/Models/CoinTransactionType.php @@ -0,0 +1,20 @@ + 'array', + ]; +} \ No newline at end of file diff --git a/api/app/Models/Game.php b/api/app/Models/Game.php index dd65b7f..13f2865 100644 --- a/api/app/Models/Game.php +++ b/api/app/Models/Game.php @@ -3,7 +3,6 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; -use App\Http\Requests\StoreGameRequest; use Illuminate\Database\Eloquent\Factories\HasFactory; diff --git a/api/app/Models/User.php b/api/app/Models/User.php index b33dc36..e0665ae 100644 --- a/api/app/Models/User.php +++ b/api/app/Models/User.php @@ -58,4 +58,9 @@ class User extends Authenticatable { return $this->hasMany(Game::class, 'player1_user_id')->orWhere('player2_user_id', $this->id); } + + public function transactions() + { + return $this->hasMany(CoinTransaction::class); + } } diff --git a/api/routes/api.php b/api/routes/api.php index 02bbaff..e7c1d06 100644 --- a/api/routes/api.php +++ b/api/routes/api.php @@ -31,6 +31,7 @@ Route::prefix('v1')->group(function () { 'updatePassword', ]); Route::post('/avatar', [ProfileController::class, 'uploadAvatar']); + Route::get('/transactions', [UserController::class, 'getMyTransactions']); }); // User Resources @@ -40,6 +41,7 @@ Route::prefix('v1')->group(function () { UserController::class, 'getMatches', ]); + Route::get('/{user}/transactions', [UserController::class, 'getTransactions']); }); // Game Resources @@ -66,6 +68,7 @@ Route::prefix('v1')->group(function () { Route::middleware('user.type:A') ->prefix('admin') ->group(function () { + Route::get('/statistics', [StatisticsController::class, 'getAdminStats']); Route::prefix('users')->group(function () { Route::get('/', [UserController::class, 'index']); Route::post('/', [UserController::class, 'store']);