mirror of
https://github.com/ryankazokas/turbovault-app.git
synced 2026-04-17 05:32:52 +00:00
Adds types
This commit is contained in:
@@ -1,7 +1,12 @@
|
||||
# typed: true
|
||||
|
||||
class GamesController < ApplicationController
|
||||
extend T::Sig
|
||||
|
||||
before_action :require_authentication
|
||||
before_action :set_game, only: [ :show, :edit, :update, :destroy ]
|
||||
|
||||
sig { void }
|
||||
def index
|
||||
@games = current_user.games.includes(:platform, :genres, :collections)
|
||||
|
||||
@@ -27,9 +32,11 @@ class GamesController < ApplicationController
|
||||
@genres = Genre.order(:name)
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def show
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def new
|
||||
@game = current_user.games.build
|
||||
@platforms = Platform.order(:name)
|
||||
@@ -37,13 +44,14 @@ class GamesController < ApplicationController
|
||||
@collections = current_user.collections.order(:name)
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def create
|
||||
@game = current_user.games.build(game_params)
|
||||
|
||||
if @game.save
|
||||
# If game was created with IGDB ID, sync the metadata
|
||||
sync_igdb_metadata_after_create if @game.igdb_id.present?
|
||||
|
||||
|
||||
redirect_to @game, notice: "Game was successfully created."
|
||||
else
|
||||
@platforms = Platform.order(:name)
|
||||
@@ -53,12 +61,14 @@ class GamesController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def edit
|
||||
@platforms = Platform.order(:name)
|
||||
@genres = Genre.order(:name)
|
||||
@collections = current_user.collections.order(:name)
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def update
|
||||
if @game.update(game_params)
|
||||
redirect_to @game, notice: "Game was successfully updated."
|
||||
@@ -70,50 +80,54 @@ class GamesController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def destroy
|
||||
@game.destroy
|
||||
redirect_to games_path, notice: "Game was successfully deleted."
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def import
|
||||
@platforms = Platform.order(:name)
|
||||
@genres = Genre.order(:name)
|
||||
@collections = current_user.collections.order(:name)
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def bulk_edit
|
||||
@game_ids = params[:game_ids] || []
|
||||
|
||||
|
||||
if @game_ids.empty?
|
||||
redirect_to games_path, alert: "Please select at least one game to edit."
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
@games = current_user.games.where(id: @game_ids)
|
||||
@platforms = Platform.order(:name)
|
||||
@genres = Genre.order(:name)
|
||||
@collections = current_user.collections.order(:name)
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def bulk_update
|
||||
@game_ids = params[:game_ids] || []
|
||||
|
||||
|
||||
if @game_ids.empty?
|
||||
redirect_to games_path, alert: "No games selected."
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
@games = current_user.games.where(id: @game_ids)
|
||||
updated_count = 0
|
||||
|
||||
|
||||
@games.each do |game|
|
||||
updates = {}
|
||||
|
||||
|
||||
# Only update fields that have values provided
|
||||
updates[:completion_status] = params[:completion_status] if params[:completion_status].present?
|
||||
updates[:location] = params[:location] if params[:location].present?
|
||||
updates[:condition] = params[:condition] if params[:condition].present?
|
||||
|
||||
|
||||
# Handle collection assignment
|
||||
if params[:collection_action].present?
|
||||
case params[:collection_action]
|
||||
@@ -129,7 +143,7 @@ class GamesController < ApplicationController
|
||||
game.collection_ids = params[:collection_ids] if params[:collection_ids].present?
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Handle genre assignment
|
||||
if params[:genre_action].present?
|
||||
case params[:genre_action]
|
||||
@@ -145,15 +159,16 @@ class GamesController < ApplicationController
|
||||
game.genre_ids = params[:genre_ids] if params[:genre_ids].present?
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if game.update(updates)
|
||||
updated_count += 1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
redirect_to games_path, notice: "Successfully updated #{updated_count} game(s)."
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def bulk_create
|
||||
require "csv"
|
||||
|
||||
@@ -163,9 +178,11 @@ class GamesController < ApplicationController
|
||||
csv_text = params[:csv_file].read
|
||||
csv = CSV.parse(csv_text, headers: true)
|
||||
|
||||
csv.each_with_index do |row, index|
|
||||
csv.each_with_index do |csv_row, index|
|
||||
# Cast to untyped to avoid Sorbet CSV::Row vs Hash confusion
|
||||
row = T.let(csv_row, T.untyped)
|
||||
platform = Platform.find_by(name: row["platform"]) || Platform.find_by(abbreviation: row["platform"])
|
||||
|
||||
|
||||
unless platform
|
||||
results[:failed] += 1
|
||||
results[:errors] << "Row #{index + 2}: Platform '#{row['platform']}' not found"
|
||||
@@ -209,10 +226,11 @@ class GamesController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def search_igdb
|
||||
query = params[:q].to_s.strip
|
||||
platform_id = params[:platform_id]
|
||||
|
||||
|
||||
if query.length < 2
|
||||
render json: []
|
||||
return
|
||||
@@ -221,15 +239,15 @@ class GamesController < ApplicationController
|
||||
begin
|
||||
service = IgdbService.new
|
||||
platform = platform_id.present? ? Platform.find_by(id: platform_id) : nil
|
||||
|
||||
|
||||
# Search IGDB (limit to 10 results for autocomplete)
|
||||
results = service.search_game(query, platform, 10)
|
||||
|
||||
|
||||
# Format results for autocomplete
|
||||
formatted_results = results.map do |result|
|
||||
# Map IGDB genres to our local genre IDs
|
||||
genre_ids = map_igdb_genres_to_ids(result[:genres] || [])
|
||||
|
||||
|
||||
{
|
||||
igdb_id: result[:igdb_id],
|
||||
name: result[:name],
|
||||
@@ -242,7 +260,7 @@ class GamesController < ApplicationController
|
||||
confidence: result[:confidence_score]
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
render json: formatted_results
|
||||
rescue => e
|
||||
Rails.logger.error("IGDB search error: #{e.message}")
|
||||
@@ -250,49 +268,53 @@ class GamesController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def search_locations
|
||||
query = params[:q].to_s.strip
|
||||
|
||||
|
||||
# Get unique locations from user's games that match the query
|
||||
locations = current_user.games
|
||||
.where.not(location: [nil, ""])
|
||||
.where.not(location: [ nil, "" ])
|
||||
.where("location ILIKE ?", "%#{query}%")
|
||||
.select(:location)
|
||||
.distinct
|
||||
.order(:location)
|
||||
.limit(10)
|
||||
.pluck(:location)
|
||||
|
||||
|
||||
render json: locations
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def search_stores
|
||||
query = params[:q].to_s.strip
|
||||
|
||||
|
||||
# Get unique digital stores from user's games that match the query
|
||||
stores = current_user.games
|
||||
.where.not(digital_store: [nil, ""])
|
||||
.where.not(digital_store: [ nil, "" ])
|
||||
.where("digital_store ILIKE ?", "%#{query}%")
|
||||
.select(:digital_store)
|
||||
.distinct
|
||||
.order(:digital_store)
|
||||
.limit(10)
|
||||
.pluck(:digital_store)
|
||||
|
||||
|
||||
render json: stores
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
sig { void }
|
||||
def set_game
|
||||
@game = current_user.games.includes(:igdb_game).find(params[:id])
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def sync_igdb_metadata_after_create
|
||||
# Fetch full game data from IGDB
|
||||
service = IgdbService.new
|
||||
igdb_data = service.get_game(@game.igdb_id)
|
||||
|
||||
|
||||
return unless igdb_data
|
||||
|
||||
# Create or update IgdbGame record
|
||||
@@ -301,11 +323,11 @@ class GamesController < ApplicationController
|
||||
ig.slug = igdb_data["slug"]
|
||||
ig.summary = igdb_data["summary"]
|
||||
ig.first_release_date = igdb_data["first_release_date"] ? Time.at(igdb_data["first_release_date"]).to_date : nil
|
||||
|
||||
|
||||
# Extract cover URL
|
||||
cover_url = igdb_data.dig("cover", "url")&.split("/")&.last&.sub(".jpg", "")
|
||||
ig.cover_url = cover_url
|
||||
|
||||
|
||||
ig.last_synced_at = Time.current
|
||||
end
|
||||
|
||||
@@ -327,9 +349,10 @@ class GamesController < ApplicationController
|
||||
Rails.logger.error("Failed to sync IGDB metadata: #{e.message}")
|
||||
end
|
||||
|
||||
sig { params(genre_names: T::Array[String]).returns(T::Array[Integer]) }
|
||||
def map_igdb_genres_to_ids(genre_names)
|
||||
return [] if genre_names.blank?
|
||||
|
||||
|
||||
# Genre mapping (same as in IgdbMatchSuggestion)
|
||||
genre_mappings = {
|
||||
"Role-playing (RPG)" => "RPG",
|
||||
@@ -352,28 +375,30 @@ class GamesController < ApplicationController
|
||||
genre_names.each do |igdb_genre_name|
|
||||
# Try exact match
|
||||
local_genre = Genre.find_by("LOWER(name) = ?", igdb_genre_name.downcase)
|
||||
|
||||
|
||||
# Try mapped name
|
||||
if local_genre.nil? && genre_mappings[igdb_genre_name]
|
||||
mapped_name = genre_mappings[igdb_genre_name]
|
||||
local_genre = Genre.find_by("LOWER(name) = ?", mapped_name.downcase)
|
||||
end
|
||||
|
||||
|
||||
genre_ids << local_genre.id if local_genre
|
||||
end
|
||||
|
||||
|
||||
genre_ids
|
||||
end
|
||||
|
||||
sig { params(genre_names: T::Array[String]).void }
|
||||
def assign_igdb_genres_to_game(genre_names)
|
||||
genre_ids = map_igdb_genres_to_ids(genre_names)
|
||||
|
||||
|
||||
genre_ids.each do |genre_id|
|
||||
genre = Genre.find(genre_id)
|
||||
@game.genres << genre unless @game.genres.include?(genre)
|
||||
end
|
||||
end
|
||||
|
||||
sig { returns(T.untyped) }
|
||||
def game_params
|
||||
params.require(:game).permit(
|
||||
:title, :platform_id, :format, :date_added, :completion_status,
|
||||
|
||||
Reference in New Issue
Block a user