unify collection api: single endpoint for all users
- restructure routes: read via /users/:id/collection/*, write via /collection/* - add user lookup + privacy check to collection_characters_controller - add race, proficiency, gender scopes to model - delete old collection_controller
This commit is contained in:
parent
301f323ee1
commit
5bc179afa8
4 changed files with 51 additions and 89 deletions
|
|
@ -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])
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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) }
|
||||
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
||||
# Collection management for current user
|
||||
# Reading collections - works for any user with privacy check
|
||||
scope 'users/:user_id' do
|
||||
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: [: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
|
||||
|
||||
# Writing to collections - requires auth, operates on current_user
|
||||
namespace :collection do
|
||||
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
|
||||
|
|
|
|||
Loading…
Reference in a new issue