diff --git a/app/controllers/api/v1/collection_characters_controller.rb b/app/controllers/api/v1/collection_characters_controller.rb index 62ff59e..ea15e1a 100644 --- a/app/controllers/api/v1/collection_characters_controller.rb +++ b/app/controllers/api/v1/collection_characters_controller.rb @@ -1,16 +1,25 @@ module Api module V1 class CollectionCharactersController < ApiController - before_action :restrict_access - before_action :set_collection_character, only: %i[show update destroy] + # Read actions: look up user from params, check privacy + before_action :set_target_user, only: %i[index show] + before_action :check_collection_access, only: %i[index show] + before_action :set_collection_character_for_read, only: %i[show] + + # Write actions: require auth, use current_user + before_action :restrict_access, only: %i[create update destroy] + before_action :set_collection_character_for_write, only: %i[update destroy] def index - @collection_characters = current_user.collection_characters + @collection_characters = @target_user.collection_characters .includes(:character, :awakening) # Apply filters @collection_characters = @collection_characters.by_element(params[:element]) if params[:element] @collection_characters = @collection_characters.by_rarity(params[:rarity]) if params[:rarity] + @collection_characters = @collection_characters.by_race(params[:race]) if params[:race] + @collection_characters = @collection_characters.by_proficiency(params[:proficiency]) if params[:proficiency] + @collection_characters = @collection_characters.by_gender(params[:gender]) if params[:gender] # Apply pagination @collection_characters = @collection_characters.paginate(page: params[:page], per_page: params[:limit] || 50) @@ -64,7 +73,26 @@ module Api private - def set_collection_character + def set_target_user + @target_user = User.find(params[:user_id]) + rescue ActiveRecord::RecordNotFound + render json: { error: "User not found" }, status: :not_found + end + + def check_collection_access + return if @target_user.nil? # Already handled by set_target_user + unless @target_user.collection_viewable_by?(current_user) + render json: { error: "You do not have permission to view this collection" }, status: :forbidden + end + end + + def set_collection_character_for_read + @collection_character = @target_user.collection_characters.find(params[:id]) + rescue ActiveRecord::RecordNotFound + raise CollectionErrors::CollectionItemNotFound.new('character', params[:id]) + end + + def set_collection_character_for_write @collection_character = current_user.collection_characters.find(params[:id]) rescue ActiveRecord::RecordNotFound raise CollectionErrors::CollectionItemNotFound.new('character', params[:id]) diff --git a/app/controllers/api/v1/collection_controller.rb b/app/controllers/api/v1/collection_controller.rb deleted file mode 100644 index 91eb10b..0000000 --- a/app/controllers/api/v1/collection_controller.rb +++ /dev/null @@ -1,79 +0,0 @@ -module Api - module V1 - class CollectionController < ApiController - before_action :set_user - before_action :check_collection_access - - # GET /api/v1/users/:user_id/collection - # GET /api/v1/users/:user_id/collection?type=weapons - def show - collection = case params[:type] - when 'characters' - { - characters: Api::V1::CollectionCharacterBlueprint.render_as_hash( - @user.collection_characters.includes(:character, :awakening), - view: :full - ) - } - when 'weapons' - { - weapons: Api::V1::CollectionWeaponBlueprint.render_as_hash( - @user.collection_weapons.includes(:weapon, :awakening, :weapon_key1, - :weapon_key2, :weapon_key3, :weapon_key4), - view: :full - ) - } - when 'summons' - { - summons: Api::V1::CollectionSummonBlueprint.render_as_hash( - @user.collection_summons.includes(:summon), - view: :full - ) - } - when 'job_accessories' - { - job_accessories: Api::V1::CollectionJobAccessoryBlueprint.render_as_hash( - @user.collection_job_accessories.includes(job_accessory: :job) - ) - } - else - # Return complete collection - { - characters: Api::V1::CollectionCharacterBlueprint.render_as_hash( - @user.collection_characters.includes(:character, :awakening), - view: :full - ), - weapons: Api::V1::CollectionWeaponBlueprint.render_as_hash( - @user.collection_weapons.includes(:weapon, :awakening, :weapon_key1, - :weapon_key2, :weapon_key3, :weapon_key4), - view: :full - ), - summons: Api::V1::CollectionSummonBlueprint.render_as_hash( - @user.collection_summons.includes(:summon), - view: :full - ), - job_accessories: Api::V1::CollectionJobAccessoryBlueprint.render_as_hash( - @user.collection_job_accessories.includes(job_accessory: :job) - ) - } - end - - render json: collection - end - - private - - def set_user - @user = User.find(params[:user_id]) - rescue ActiveRecord::RecordNotFound - render json: { error: "User not found" }, status: :not_found - end - - def check_collection_access - unless @user.collection_viewable_by?(current_user) - render json: { error: "You do not have permission to view this collection" }, status: :forbidden - end - end - end - end -end \ No newline at end of file diff --git a/app/models/collection_character.rb b/app/models/collection_character.rb index 3951ba8..457280a 100644 --- a/app/models/collection_character.rb +++ b/app/models/collection_character.rb @@ -16,6 +16,13 @@ class CollectionCharacter < ApplicationRecord scope :by_element, ->(element) { joins(:character).where(characters: { element: element }) } scope :by_rarity, ->(rarity) { joins(:character).where(characters: { rarity: rarity }) } + scope :by_race, ->(races) { + joins(:character).where('characters.race1 IN (?) OR characters.race2 IN (?)', races, races) + } + scope :by_proficiency, ->(proficiencies) { + joins(:character).where('characters.proficiency1 IN (?) OR characters.proficiency2 IN (?)', proficiencies, proficiencies) + } + scope :by_gender, ->(genders) { joins(:character).where(characters: { gender: genders }) } scope :transcended, -> { where('transcendence_step > 0') } scope :with_awakening, -> { where.not(awakening_id: nil) } diff --git a/config/routes.rb b/config/routes.rb index 9879874..ffc75b5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -126,14 +126,20 @@ Rails.application.routes.draw do delete 'favorites', to: 'favorites#destroy' - # User collection viewing (respects privacy settings) - get 'users/:user_id/collection', to: 'collection#show' + # Reading collections - works for any user with privacy check + scope 'users/:user_id' do + namespace :collection do + resources :characters, only: [:index, :show], controller: '/api/v1/collection_characters' + resources :weapons, only: [:index, :show], controller: '/api/v1/collection_weapons' + resources :summons, only: [:index, :show], controller: '/api/v1/collection_summons' + end + end - # Collection management for current user + # Writing to collections - requires auth, operates on current_user namespace :collection do - resources :characters, controller: '/api/v1/collection_characters' - resources :weapons, controller: '/api/v1/collection_weapons' - resources :summons, controller: '/api/v1/collection_summons' + resources :characters, only: [:create, :update, :destroy], controller: '/api/v1/collection_characters' + resources :weapons, only: [:create, :update, :destroy], controller: '/api/v1/collection_weapons' + resources :summons, only: [:create, :update, :destroy], controller: '/api/v1/collection_summons' resources :job_accessories, controller: '/api/v1/collection_job_accessories', only: [:index, :show, :create, :destroy] end