lots of progress
This commit is contained in:
@@ -40,12 +40,7 @@ class BuildGameLibrary extends Command
|
||||
$startTimestamp = strtotime("{$year}-01-01");
|
||||
$endTimestamp = strtotime("{$year}-12-31");
|
||||
|
||||
// Generate a random query to get diverse results
|
||||
$query = $this->generateRandomQuery();
|
||||
|
||||
$this->info("Searching for games from {$year} with query: {$query}");
|
||||
|
||||
$games = $igdbService->get();
|
||||
$games = $igdbService->get($limit);
|
||||
|
||||
if (empty($games)) {
|
||||
$this->warn("No games found for this batch. Moving to next batch...");
|
||||
@@ -66,6 +61,7 @@ class BuildGameLibrary extends Command
|
||||
$totalAdded++;
|
||||
} catch (\Exception $e) {
|
||||
$this->warn("\nFailed to process game: {$e->getMessage()}");
|
||||
dd($e);
|
||||
$totalSkipped++;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use JetBrains\PhpStorm\NoReturn;
|
||||
use ZipArchive;
|
||||
|
||||
class FetchIgdbDumps extends Command
|
||||
@@ -68,6 +69,7 @@ class FetchIgdbDumps extends Command
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
#[NoReturn]
|
||||
private function fetchDumps(string $type, int $limit, int $offset, string $outputDir, IgdbAuthService $authService): void
|
||||
{
|
||||
$endpoint = self::ENDPOINTS[$type];
|
||||
@@ -81,13 +83,13 @@ class FetchIgdbDumps extends Command
|
||||
$accessToken = $authService->getAccessToken();
|
||||
|
||||
$response = Http::withHeaders([
|
||||
'Client-ID' => config('services.igdb.credentials.client_id'),
|
||||
'Client-ID' => config('igdb.credentials.client_id'),
|
||||
'Authorization' => 'Bearer ' . $accessToken,
|
||||
])->post($endpoint, [
|
||||
'fields' => $fields,
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
'where' => 'rating_count > 0',
|
||||
// 'where' => 'rating_count > 0',
|
||||
]);
|
||||
|
||||
if (!$response->successful()) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
abstract class Controller
|
||||
abstract class Controller extends \Illuminate\Routing\Controller
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
@@ -29,4 +29,79 @@ class GameController extends Controller
|
||||
|
||||
return response()->json($game, 201);
|
||||
}
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$query = Game::query();
|
||||
|
||||
// Apply search
|
||||
if ($request->has('search')) {
|
||||
$search = $request->get('search');
|
||||
$query->where(function($q) use ($search) {
|
||||
$q->where('name', 'like', "%{$search}%")
|
||||
->orWhere('summary', 'like', "%{$search}%");
|
||||
});
|
||||
}
|
||||
|
||||
// Apply sorting
|
||||
$sort = $request->get('sort', 'first_release_date');
|
||||
$direction = $request->get('direction', 'desc');
|
||||
|
||||
if ($sort === 'rating') {
|
||||
$query->orderBy('rating', $direction);
|
||||
} elseif ($sort === 'rating_count') {
|
||||
$query->orderBy('rating_count', $direction);
|
||||
} else {
|
||||
$query->orderBy('first_release_date', $direction);
|
||||
}
|
||||
|
||||
// Apply filters
|
||||
if ($request->has('platform')) {
|
||||
$query->whereHas('platforms', function ($q) use ($request) {
|
||||
$q->where('slug', $request->platform);
|
||||
});
|
||||
}
|
||||
|
||||
if ($request->has('genre')) {
|
||||
$query->whereHas('genres', function ($q) use ($request) {
|
||||
$q->where('slug', $request->genre);
|
||||
});
|
||||
}
|
||||
|
||||
if ($request->has('year')) {
|
||||
$query->whereYear('first_release_date', $request->year);
|
||||
}
|
||||
|
||||
if ($request->has('rating_range')) {
|
||||
$range = explode('-', $request->rating_range);
|
||||
if (count($range) === 2) {
|
||||
$min = (float)$range[0];
|
||||
$max = (float)$range[1];
|
||||
$query->whereBetween('rating', [$min, $max]);
|
||||
}
|
||||
}
|
||||
|
||||
$games = $query->paginate(12)->withQueryString();
|
||||
|
||||
// Get data for filter dropdowns
|
||||
$platforms = \App\Models\Platform::orderBy('name')->get();
|
||||
$genres = \App\Models\Genre::orderBy('name')->get();
|
||||
|
||||
// Get unique years from games
|
||||
$years = Game::selectRaw('YEAR(first_release_date) as year')
|
||||
->whereNotNull('first_release_date')
|
||||
->distinct()
|
||||
->orderBy('year', 'desc')
|
||||
->pluck('year')
|
||||
->filter()
|
||||
->values();
|
||||
|
||||
return view('games.index', compact('games', 'platforms', 'genres', 'years'));
|
||||
}
|
||||
|
||||
public function show(Game $game)
|
||||
{
|
||||
$game->load(['platforms', 'genres', 'screenshots', 'videos', 'similar_games', 'dlcs', 'reviews.user']);
|
||||
return view('games.show', compact('game'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Game;
|
||||
use App\Models\GameList;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class GameListController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$lists = Auth::user()->lists()->withCount('games')->get();
|
||||
return view('lists.index', compact('lists'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('lists.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'nullable|string'
|
||||
]);
|
||||
|
||||
Auth::user()->lists()->create([
|
||||
'name' => $request->name,
|
||||
'description' => $request->description
|
||||
]);
|
||||
|
||||
return redirect()->route('lists.index')->with('success', 'List created successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(GameList $list)
|
||||
{
|
||||
$this->authorize('view', $list);
|
||||
|
||||
$games = $list->games()->paginate(12);
|
||||
return view('lists.show', compact('list', 'games'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(GameList $list)
|
||||
{
|
||||
$this->authorize('update', $list);
|
||||
return view('lists.edit', compact('list'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, GameList $list)
|
||||
{
|
||||
$this->authorize('update', $list);
|
||||
|
||||
$request->validate([
|
||||
'name' => 'required|string|max:255',
|
||||
'description' => 'nullable|string'
|
||||
]);
|
||||
|
||||
$list->update([
|
||||
'name' => $request->name,
|
||||
'description' => $request->description
|
||||
]);
|
||||
|
||||
return redirect()->route('lists.show', $list)->with('success', 'List updated successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(GameList $list)
|
||||
{
|
||||
$this->authorize('delete', $list);
|
||||
|
||||
if ($list->is_default) {
|
||||
return redirect()->back()->with('error', 'Cannot delete default lists.');
|
||||
}
|
||||
|
||||
$list->delete();
|
||||
return redirect()->route('lists.index')->with('success', 'List deleted successfully.');
|
||||
}
|
||||
|
||||
public function addGame(Request $request, GameList $list)
|
||||
{
|
||||
$this->authorize('update', $list);
|
||||
|
||||
$request->validate([
|
||||
'game_id' => 'required|exists:games,id'
|
||||
]);
|
||||
|
||||
$list->games()->attach($request->game_id);
|
||||
|
||||
return redirect()->back()->with('success', 'Game added to list successfully.');
|
||||
}
|
||||
|
||||
public function removeGame(GameList $list, Game $game)
|
||||
{
|
||||
$this->authorize('update', $list);
|
||||
|
||||
$list->games()->detach($game->id);
|
||||
|
||||
return redirect()->back()->with('success', 'Game removed from list successfully.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Game;
|
||||
use App\Models\Review;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ReviewController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth', ['except' => ['index', 'show']]);
|
||||
}
|
||||
|
||||
public function index(Game $game)
|
||||
{
|
||||
$reviews = $game->reviews()->with('user')->latest()->paginate(10);
|
||||
return view('reviews.index', compact('game', 'reviews'));
|
||||
}
|
||||
|
||||
public function create(Game $game)
|
||||
{
|
||||
return view('reviews.create', compact('game'));
|
||||
}
|
||||
|
||||
public function store(Request $request, Game $game)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'content' => 'required|string|min:10|max:1000',
|
||||
'recommended' => 'required|boolean',
|
||||
'rating' => 'required|integer|between:1,10',
|
||||
]);
|
||||
|
||||
$review = new Review($validated);
|
||||
$review->user_id = Auth::id();
|
||||
$review->game_id = $game->id;
|
||||
$review->save();
|
||||
|
||||
return redirect()->route('games.show', $game->slug)
|
||||
->with('success', 'Review posted successfully!');
|
||||
}
|
||||
|
||||
public function show(Game $game, Review $review)
|
||||
{
|
||||
return view('reviews.show', compact('game', 'review'));
|
||||
}
|
||||
|
||||
public function edit(Game $game, Review $review)
|
||||
{
|
||||
$this->authorize('update', $review);
|
||||
return view('reviews.edit', compact('game', 'review'));
|
||||
}
|
||||
|
||||
public function update(Request $request, Game $game, Review $review)
|
||||
{
|
||||
$this->authorize('update', $review);
|
||||
|
||||
$validated = $request->validate([
|
||||
'content' => 'required|string|min:10|max:1000',
|
||||
'recommended' => 'required|boolean',
|
||||
'rating' => 'required|integer|between:1,10',
|
||||
]);
|
||||
|
||||
$review->update($validated);
|
||||
|
||||
return redirect()->route('games.show', $game->slug)
|
||||
->with('success', 'Review updated successfully!');
|
||||
}
|
||||
|
||||
public function destroy(Game $game, Review $review)
|
||||
{
|
||||
$this->authorize('delete', $review);
|
||||
$review->delete();
|
||||
|
||||
return redirect()->route('games.show', $game->slug)
|
||||
->with('success', 'Review deleted successfully!');
|
||||
}
|
||||
}
|
||||
+74
-3
@@ -5,6 +5,7 @@ namespace App\Models;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class Game extends Model
|
||||
{
|
||||
@@ -34,11 +35,81 @@ class Game extends Model
|
||||
|
||||
public function genres(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Genre::class);
|
||||
return $this->belongsToMany(Genre::class, 'game_genre', 'game_id', 'genre_id');
|
||||
}
|
||||
|
||||
public function platforms(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Platform::class);
|
||||
return $this->belongsToMany(Platform::class, 'game_platform', 'game_id', 'platform_id');
|
||||
}
|
||||
}
|
||||
|
||||
public function screenshots(): HasMany
|
||||
{
|
||||
return $this->hasMany(Screenshot::class);
|
||||
}
|
||||
|
||||
public function videos(): HasMany
|
||||
{
|
||||
return $this->hasMany(Video::class);
|
||||
}
|
||||
|
||||
public function bundles(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Game::class, 'game_bundles', 'game_id', 'bundle_id');
|
||||
}
|
||||
|
||||
public function collections(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Game::class, 'game_collections', 'game_id', 'collection_id');
|
||||
}
|
||||
|
||||
public function dlcs(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Game::class, 'game_dlcs', 'game_id', 'dlc_id');
|
||||
}
|
||||
|
||||
public function expansions(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Game::class, 'game_expansions', 'game_id', 'expansion_id');
|
||||
}
|
||||
|
||||
public function franchises(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Game::class, 'game_franchises', 'game_id', 'franchise_id');
|
||||
}
|
||||
|
||||
public function ports(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Game::class, 'game_ports', 'game_id', 'port_id');
|
||||
}
|
||||
|
||||
public function remakes(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Game::class, 'game_remakes', 'game_id', 'remake_id');
|
||||
}
|
||||
|
||||
public function similar_games(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Game::class, 'game_similar', 'game_id', 'similar_game_id');
|
||||
}
|
||||
|
||||
public function reviews(): HasMany
|
||||
{
|
||||
return $this->hasMany(Review::class);
|
||||
}
|
||||
|
||||
public function ratings()
|
||||
{
|
||||
return $this->hasMany(Rating::class);
|
||||
}
|
||||
|
||||
public function lists()
|
||||
{
|
||||
return $this->belongsToMany(GameList::class)->withTimestamps();
|
||||
}
|
||||
|
||||
public function averageRating()
|
||||
{
|
||||
return $this->ratings()->avg('rating');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class GameList extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'name',
|
||||
'slug',
|
||||
'description',
|
||||
'is_default'
|
||||
];
|
||||
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::creating(function ($list) {
|
||||
$list->slug = Str::slug($list->name);
|
||||
});
|
||||
|
||||
static::updating(function ($list) {
|
||||
$list->slug = Str::slug($list->name);
|
||||
});
|
||||
}
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function games(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Game::class)->withTimestamps();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Rating extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'game_id',
|
||||
'rating',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'rating' => 'integer',
|
||||
];
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function game(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Game::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Review extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'game_id',
|
||||
'content',
|
||||
'recommended',
|
||||
'rating',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'recommended' => 'boolean',
|
||||
'rating' => 'integer',
|
||||
];
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
public function game(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Game::class);
|
||||
}
|
||||
}
|
||||
+35
-5
@@ -6,6 +6,7 @@ namespace App\Models;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
@@ -38,11 +39,40 @@ class User extends Authenticatable
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
protected $casts = [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
];
|
||||
|
||||
public function reviews(): HasMany
|
||||
{
|
||||
return [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
];
|
||||
return $this->hasMany(Review::class);
|
||||
}
|
||||
|
||||
public function ratings(): HasMany
|
||||
{
|
||||
return $this->hasMany(Rating::class);
|
||||
}
|
||||
|
||||
public function lists()
|
||||
{
|
||||
return $this->hasMany(GameList::class);
|
||||
}
|
||||
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::created(function ($user) {
|
||||
// Create default lists
|
||||
$defaultLists = [
|
||||
['name' => 'Played Games', 'is_default' => true],
|
||||
['name' => 'Want to Play', 'is_default' => true]
|
||||
];
|
||||
|
||||
foreach ($defaultLists as $list) {
|
||||
$user->lists()->create($list);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\GameList;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\Response;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class GameListPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*/
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*/
|
||||
public function view(User $user, GameList $list)
|
||||
{
|
||||
return $user->id === $list->user_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*/
|
||||
public function create(User $user): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*/
|
||||
public function update(User $user, GameList $list)
|
||||
{
|
||||
return $user->id === $list->user_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*/
|
||||
public function delete(User $user, GameList $list)
|
||||
{
|
||||
return $user->id === $list->user_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the model.
|
||||
*/
|
||||
public function restore(User $user, GameList $gameList): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete the model.
|
||||
*/
|
||||
public function forceDelete(User $user, GameList $gameList): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\Review;
|
||||
use App\Models\User;
|
||||
use Illuminate\Auth\Access\Response;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class ReviewPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
/**
|
||||
* Determine whether the user can view any models.
|
||||
*/
|
||||
public function viewAny(User $user): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
*/
|
||||
public function view(User $user, Review $review): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create models.
|
||||
*/
|
||||
public function create(User $user): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
*/
|
||||
public function update(User $user, Review $review): bool
|
||||
{
|
||||
return $user->id === $review->user_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
*/
|
||||
public function delete(User $user, Review $review): bool
|
||||
{
|
||||
return $user->id === $review->user_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can restore the model.
|
||||
*/
|
||||
public function restore(User $user, Review $review): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can permanently delete the model.
|
||||
*/
|
||||
public function forceDelete(User $user, Review $review): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Pagination\Paginator;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
@@ -19,6 +20,6 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
//
|
||||
Paginator::useBootstrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use Illuminate\Support\Facades\Log;
|
||||
class IgdbAuthService
|
||||
{
|
||||
private const TOKEN_CACHE_KEY = 'igdb_access_token';
|
||||
private const TOKEN_EXPIRY = 3600; // 1 hour in seconds
|
||||
private const TOKEN_EXPIRY = 3600*24*31; // 1 month in seconds
|
||||
|
||||
public function getAccessToken(): string
|
||||
{
|
||||
@@ -21,13 +21,30 @@ class IgdbAuthService
|
||||
private function fetchNewAccessToken(): string
|
||||
{
|
||||
try {
|
||||
$response = Http::post('https://id.twitch.tv/oauth2/token', [
|
||||
'client_id' => config('services.igdb.client_id'),
|
||||
'client_secret' => config('services.igdb.client_secret'),
|
||||
// Log the config values to debug
|
||||
Log::info('IGDB Auth Attempt', [
|
||||
'client_id' => config('services.igdb.credentials.client_id'),
|
||||
'client_secret' => config('services.igdb.credentials.client_secret')
|
||||
]);
|
||||
|
||||
$clientId = config('igdb.credentials.client_id');
|
||||
$clientSecret = config('igdb.credentials.client_secret');
|
||||
|
||||
if (empty($clientId) || empty($clientSecret)) {
|
||||
throw new \Exception("IGDB credentials are not properly configured");
|
||||
}
|
||||
|
||||
$response = Http::asForm()->post('https://id.twitch.tv/oauth2/token', [
|
||||
'client_id' => $clientId,
|
||||
'client_secret' => $clientSecret,
|
||||
'grant_type' => 'client_credentials',
|
||||
]);
|
||||
|
||||
if (!$response->successful()) {
|
||||
Log::error('IGDB Auth Response', [
|
||||
'status' => $response->status(),
|
||||
'body' => $response->body()
|
||||
]);
|
||||
throw new \Exception("Failed to get access token: " . $response->body());
|
||||
}
|
||||
|
||||
@@ -40,4 +57,4 @@ class IgdbAuthService
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+100
-34
@@ -17,7 +17,7 @@ use MarcReichel\IGDBLaravel\Models\Platform as IgdbPlatform;
|
||||
|
||||
class IgdbService
|
||||
{
|
||||
public function get()
|
||||
public function get(int $limit)
|
||||
{
|
||||
try {
|
||||
$existingIds = $this->getExistingIds();
|
||||
@@ -26,7 +26,7 @@ class IgdbService
|
||||
'id',
|
||||
'name',
|
||||
'summary',
|
||||
'cover.url',
|
||||
'cover',
|
||||
'slug',
|
||||
'genres',
|
||||
'platforms',
|
||||
@@ -34,17 +34,21 @@ class IgdbService
|
||||
'rating',
|
||||
'rating_count'
|
||||
])
|
||||
->where('rating_count', '>', 0)
|
||||
->where('category', '=', 0);
|
||||
// ->where('rating_count', '>', 0)
|
||||
// ->where('category', '=', 0)
|
||||
;
|
||||
|
||||
if (!empty($existingIds)) {
|
||||
$queryBuilder = $queryBuilder->whereNotIn('id', array_map(function($id) {
|
||||
return (int)str_replace('"', '', $id);
|
||||
}, $existingIds));
|
||||
// Convert array of quoted strings to array of integers
|
||||
// $existingIds = array_map(function($id) {
|
||||
// return (int)str_replace('"', '', $id);
|
||||
// }, $existingIds);
|
||||
$queryBuilder->whereNotIn('id', $existingIds);
|
||||
}
|
||||
|
||||
$a = $queryBuilder
|
||||
->limit(50)
|
||||
->orderBy('first_release_date', 'asc')
|
||||
->limit($limit)
|
||||
->get();
|
||||
}catch (\Throwable $e) {
|
||||
dd(
|
||||
@@ -68,12 +72,13 @@ class IgdbService
|
||||
|
||||
/** @var Game $existingGame */
|
||||
foreach ($existingGames as $existingGame) {
|
||||
$existingIds[] = (string)$existingGame->id;
|
||||
$existingIds[] = (string)$existingGame->igdb_id;
|
||||
}
|
||||
|
||||
return array_map(function($id) {
|
||||
return '"'.$id.'"';
|
||||
}, $existingIds);
|
||||
return $existingIds;
|
||||
// return array_map(function($id) {
|
||||
// return '"'.$id.'"';
|
||||
// }, $existingIds);
|
||||
}
|
||||
|
||||
public function searchGames(string $query, int $limit = 10, ?int $startTimestamp = null, ?int $endTimestamp = null): array
|
||||
@@ -240,13 +245,41 @@ class IgdbService
|
||||
}
|
||||
}
|
||||
|
||||
// Process genres
|
||||
$genres = [];
|
||||
if (isset($gameData->genres) && is_array($gameData->genres)) {
|
||||
$genreData = IgdbGenre::select(['id', 'name', 'slug'])
|
||||
->whereIn('id', $gameData->genres)
|
||||
->get();
|
||||
|
||||
foreach ($genreData as $genreDetails) {
|
||||
$genre = Genre::updateOrCreate(
|
||||
['igdb_id' => $genreDetails->id],
|
||||
[
|
||||
'name' => $genreDetails->name,
|
||||
'slug' => $genreDetails->slug,
|
||||
]
|
||||
);
|
||||
$genres[] = $genre->id;
|
||||
}
|
||||
}
|
||||
|
||||
$cover = Cover::where('game', '=', $gameData->id)->first();
|
||||
|
||||
$coverUrl = null;
|
||||
|
||||
if ($cover) {
|
||||
$coverUrl = 'https:'.$cover->url;
|
||||
$coverUrl = str_replace('t_thumb', 't_cover_big', $coverUrl);
|
||||
}
|
||||
|
||||
// Create or update the game
|
||||
$game = Game::updateOrCreate(
|
||||
['igdb_id' => $gameData->id],
|
||||
[
|
||||
'name' => $gameData->name,
|
||||
'summary' => $gameData->summary ?? null,
|
||||
'cover_url' => $gameData->cover?->url ?? null,
|
||||
'cover_url' => $coverUrl,
|
||||
'slug' => $gameData->slug,
|
||||
'first_release_date' => $gameData->first_release_date ?? null,
|
||||
'rating' => $gameData->rating ?? null,
|
||||
@@ -254,12 +287,20 @@ class IgdbService
|
||||
]
|
||||
);
|
||||
|
||||
// Sync platforms and genres
|
||||
if (!empty($platforms)) {
|
||||
$game->platforms()->sync($platforms);
|
||||
}
|
||||
if (!empty($genres)) {
|
||||
$game->genres()->sync($genres);
|
||||
}
|
||||
|
||||
// Process artworks
|
||||
try {
|
||||
$artworks = \MarcReichel\IGDBLaravel\Models\Artwork::select([
|
||||
'id',
|
||||
'url',
|
||||
'width',
|
||||
'width',
|
||||
'height',
|
||||
'image_id'
|
||||
])
|
||||
@@ -285,11 +326,6 @@ class IgdbService
|
||||
]);
|
||||
}
|
||||
|
||||
// Process platforms relationship
|
||||
if (!empty($platforms)) {
|
||||
$game->platforms()->sync($platforms);
|
||||
}
|
||||
|
||||
// Process screenshots
|
||||
try {
|
||||
$screenshots = \MarcReichel\IGDBLaravel\Models\Screenshot::select([
|
||||
@@ -325,7 +361,7 @@ class IgdbService
|
||||
try {
|
||||
$videos = \MarcReichel\IGDBLaravel\Models\GameVideo::select([
|
||||
'id',
|
||||
'name',
|
||||
'name',
|
||||
'video_id',
|
||||
'url',
|
||||
'checksum'
|
||||
@@ -365,25 +401,55 @@ class IgdbService
|
||||
throw new \InvalidArgumentException('Game data must be an instance of IgdbGame');
|
||||
}
|
||||
|
||||
// Fetch related games data using IGDB API
|
||||
$relationships = [
|
||||
'bundles' => IgdbGame::select(['id'])->where('id', 'in', $gameData->bundles ?? [])->get()->pluck('id')->toArray(),
|
||||
'collections' => IgdbGame::select(['id'])->where('id', 'in', $gameData->collections ?? [])->get()->pluck('id')->toArray(),
|
||||
'dlcs' => IgdbGame::select(['id'])->where('id', 'in', $gameData->dlcs ?? [])->get()->pluck('id')->toArray(),
|
||||
'expanded_games' => IgdbGame::select(['id'])->where('id', 'in', $gameData->expanded_games ?? [])->get()->pluck('id')->toArray(),
|
||||
'franchises' => IgdbGame::select(['id'])->where('id', 'in', $gameData->franchises ?? [])->get()->pluck('id')->toArray(),
|
||||
'ports' => IgdbGame::select(['id'])->where('id', 'in', $gameData->ports ?? [])->get()->pluck('id')->toArray(),
|
||||
'remakes' => IgdbGame::select(['id'])->where('id', 'in', $gameData->remakes ?? [])->get()->pluck('id')->toArray(),
|
||||
'similar_games' => IgdbGame::select(['id'])->where('id', 'in', $gameData->similar_games ?? [])->get()->pluck('id')->toArray(),
|
||||
// Initialize relationships array
|
||||
$relationships = [];
|
||||
|
||||
// Define relationship mappings and check each one
|
||||
$relationshipMappings = [
|
||||
'bundles',
|
||||
'collections',
|
||||
'dlcs',
|
||||
'expanded_games',
|
||||
'franchises',
|
||||
'ports',
|
||||
'remakes',
|
||||
'similar_games'
|
||||
];
|
||||
|
||||
foreach ($relationships as $igdbKey => $relationship) {
|
||||
// Only query IGDB for relationships that have data
|
||||
foreach ($relationshipMappings as $relationship) {
|
||||
if (!empty($gameData->$relationship)) {
|
||||
$relationships[$relationship] = IgdbGame::select(['id'])
|
||||
->where('id', 'in', $gameData->$relationship)
|
||||
->get()
|
||||
->pluck('id')
|
||||
->toArray();
|
||||
} else {
|
||||
$relationships[$relationship] = [];
|
||||
}
|
||||
}
|
||||
|
||||
// Process and sync each relationship
|
||||
foreach ($relationships as $igdbKey => $relatedIds) {
|
||||
// Convert IGDB relationship key to Laravel relationship method
|
||||
$relationshipMethod = str_replace('_', '', $igdbKey); // Remove underscores
|
||||
|
||||
$relatedGames = [];
|
||||
if (isset($gameData->$igdbKey) && !empty($gameData->$igdbKey)) {
|
||||
$relatedIds = collect($gameData->$igdbKey)->pluck('id')->toArray();
|
||||
if (!empty($relatedIds)) {
|
||||
$relatedGames = Game::whereIn('igdb_id', $relatedIds)->pluck('id')->toArray();
|
||||
}
|
||||
$game->$relationship()->sync($relatedGames);
|
||||
|
||||
// Only sync if the relationship method exists
|
||||
if (method_exists($game, $relationshipMethod)) {
|
||||
Log::info("Syncing relationship '$relationshipMethod' for game {$game->id}");
|
||||
|
||||
$game->$relationshipMethod()->sync($relatedGames);
|
||||
} else {
|
||||
Log::warning("Relationship method '$relationshipMethod' does not exist on Game model", [
|
||||
'game_id' => $game->id,
|
||||
'igdb_key' => $igdbKey
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user