From 010f64264f86d8c22ef0f7e98696e8409449154b Mon Sep 17 00:00:00 2001 From: Matchu Date: Sat, 11 Nov 2023 07:14:48 -0800 Subject: [PATCH] Replace swf_assets#index with item_appearances#index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Preparing a better endpoint for wardrobe-2020 to use! I deleted the now-unused swf_assets#index endpoint, and replaced it with an "appearances" concept that isn't exactly reflected in the database models but is a _lot_ easier for clients to work with imo. Note that this was a big part of the motivation for the recent `manifest_url` work—in this draft, I'm probably gonna have the client request the manifest, rather than use impress-2020's trick of caching it in the database! There's a bit of a perf penalty, but I think that's a simpler starting point, and I have a hunch I'll be able to make up the perf difference once we have the impress-media-server managing more of these responsibilities. --- .../item_appearances_controller.rb | 6 ++ app/controllers/swf_assets_controller.rb | 56 ------------------- app/models/item.rb | 33 +++++++---- app/models/swf_asset.rb | 38 ++++++++----- app/models/zone.rb | 4 ++ config/routes.rb | 11 +--- 6 files changed, 58 insertions(+), 90 deletions(-) create mode 100644 app/controllers/item_appearances_controller.rb diff --git a/app/controllers/item_appearances_controller.rb b/app/controllers/item_appearances_controller.rb new file mode 100644 index 00000000..be8edabb --- /dev/null +++ b/app/controllers/item_appearances_controller.rb @@ -0,0 +1,6 @@ +class ItemAppearancesController < ApplicationController + def index + @item = Item.find(params[:item_id]) + render json: @item.appearances + end +end diff --git a/app/controllers/swf_assets_controller.rb b/app/controllers/swf_assets_controller.rb index 8713837f..9229c207 100644 --- a/app/controllers/swf_assets_controller.rb +++ b/app/controllers/swf_assets_controller.rb @@ -1,60 +1,4 @@ class SwfAssetsController < ApplicationController - def index - if params[:item_id] - item = Item.find(params[:item_id]) - @swf_assets = item.swf_assets.includes_depth - if params[:body_id] - @swf_assets = @swf_assets.fitting_body_id(params[:body_id]) - else - if item.special_color - @swf_assets = @swf_assets.fitting_color(item.special_color) - else - @swf_assets = @swf_assets.fitting_standard_body_ids - end - json = @swf_assets.all.group_by(&:body_id) - end - elsif params[:pet_type_id] && params[:item_ids] - pet_type = PetType.find(params[:pet_type_id]) - - @swf_assets = SwfAsset.object_assets.includes_depth. - fitting_body_id(pet_type.body_id). - for_item_ids(params[:item_ids]). - with_parent_ids - json = @swf_assets.map { |a| a.as_json(:parent_id => a.parent_id.to_i, :for => 'wardrobe') } - elsif params[:pet_state_id] - @swf_assets = PetState.find(params[:pet_state_id]).swf_assets. - includes_depth.all - pet_state_id = params[:pet_state_id].to_i - json = @swf_assets.map { |a| a.as_json(:parent_id => pet_state_id, :for => 'wardrobe') } - elsif params[:pet_type_id] - @swf_assets = PetType.find(params[:pet_type_id]).pet_states.emotion_order - .first.swf_assets.includes_depth - elsif params[:ids] - @swf_assets = [] - if params[:ids][:biology] - @swf_assets += SwfAsset.includes_depth.biology_assets.where(:remote_id => params[:ids][:biology]).all - end - if params[:ids][:object] - @swf_assets += SwfAsset.includes_depth.object_assets.where(:remote_id => params[:ids][:object]).all - end - elsif params[:body_id] && params[:item_ids] - # DEPRECATED in favor of pet_type_id and item_ids - swf_assets = SwfAsset.arel_table - @swf_assets = SwfAsset.includes_depth.object_assets. - select('swf_assets.*, parents_swf_assets.parent_id'). - fitting_body_id(params[:body_id]). - for_item_ids(params[:item_ids]) - json = @swf_assets.map { |a| a.as_json(:parent_id => a.parent_id.to_i, :for => 'wardrobe') } - end - if @swf_assets - @swf_assets = @swf_assets.all unless @swf_assets.is_a? Array - json = @swf_assets unless json - else - json = nil - end - render :json => json - end - def show @swf_asset = SwfAsset.find params[:id] render :json => @swf_asset diff --git a/app/models/item.rb b/app/models/item.rb index a842e53e..fff00c66 100644 --- a/app/models/item.rb +++ b/app/models/item.rb @@ -511,17 +511,30 @@ class Item < ApplicationRecord def parent_swf_asset_relationships_to_update=(rels) @parent_swf_asset_relationships_to_update = rels end - - def needed_translations - translatable_locales = Set.new(I18n.locales_with_neopets_language_code) - translated_locales = Set.new(translations.map(&:locale)) - translatable_locales - translated_locales - end - def method_cached?(method_name) - # No methods are cached on a full item. This is for duck typing with item - # proxies. - false + Appearance = Struct.new(:body_id, :swf_assets) + def appearances + all_swf_assets = swf_assets.to_a + + # If there are no assets yet, there are no appearances. + return [] if all_swf_assets.empty? + + # Get all SWF assets, and separate the ones that fit everyone (body_id=0). + swf_assets_by_body_id = all_swf_assets.group_by(&:body_id) + swf_assets_for_all_bodies = swf_assets_by_body_id.delete(0) || [] + + # If there are no body-specific assets, return one appearance for them all. + if swf_assets_by_body_id.empty? + return Appearance.new(0, swf_assets_for_all_bodies) + end + + # Otherwise, create an appearance for each real (nonzero) body ID. We don't + # generally expect body_id = 0 and body_id != 0 to mix, but if they do, + # uhh, let's merge the body_id = 0 ones in? + swf_assets_by_body_id.map do |body_id, body_specific_assets| + swf_assets_for_body = body_specific_assets + swf_assets_for_all_bodies + Appearance.new(body_id, swf_assets_for_body) + end end def self.all_by_ids_or_children(ids, swf_assets) diff --git a/app/models/swf_asset.rb b/app/models/swf_asset.rb index dc8a763c..89179685 100644 --- a/app/models/swf_asset.rb +++ b/app/models/swf_asset.rb @@ -96,22 +96,30 @@ class SwfAsset < ApplicationRecord end def as_json(options={}) - json = { - :id => remote_id, - :type => type, - :depth => depth, - :body_id => body_id, - :zone_id => zone_id, - :zones_restrict => zones_restrict, - :is_body_specific => body_specific?, - # Now that we don't proactively convert images anymore, let's just always - # say `has_image: true` when sending data to the frontend, so it'll use the - # new URLs anyway! - :has_image => true, - :images => images + super({ + only: [:id], + methods: [:zone, :restricted_zones, :urls] + }.merge(options)) + end + + def urls + { + swf: url, + png: image_url, + manifest: manifest_url, } - json[:parent_id] = options[:parent_id] if options[:parent_id] - json + end + + def restricted_zone_ids + [].tap do |ids| + zones_restrict.chars.each_with_index do |bit, index| + ids << index + 1 if bit == "1" + end + end + end + + def restricted_zones + Zone.where(id: restricted_zone_ids) end def body_specific? diff --git a/app/models/zone.rb b/app/models/zone.rb index 887fba03..cf4050d1 100644 --- a/app/models/zone.rb +++ b/app/models/zone.rb @@ -18,6 +18,10 @@ class Zone < ActiveRecord::Base } scope :for_items, -> { where(arel_table[:type_id].gt(1)) } + def as_json(options={}) + super({only: [:id, :depth, :label]}.merge(options)) + end + def uncertain_label @sometimes ? "#{label} sometimes" : label end diff --git a/config/routes.rb b/config/routes.rb index 0ed310c7..3d02b1e6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -7,25 +7,18 @@ OpenneoImpressItems::Application.routes.draw do get '/wardrobe' => redirect('/outfits/new') get '/start/:color_name/:species_name' => 'outfits#start' - # DEPRECATED - get '/bodies/:body_id/swf_assets.json' => 'swf_assets#index', :as => :body_swf_assets - - get '/items/:item_id/swf_assets.json' => 'swf_assets#index', :as => :item_swf_assets - get '/items/:item_id/bodies/:body_id/swf_assets.json' => 'swf_assets#index', :as => :item_swf_assets_for_body_id - get '/pet_types/:pet_type_id/swf_assets.json' => 'swf_assets#index', :as => :pet_type_swf_assets - get '/pet_types/:pet_type_id/items/swf_assets.json' => 'swf_assets#index', :as => :item_swf_assets_for_pet_type - get '/pet_states/:pet_state_id/swf_assets.json' => 'swf_assets#index', :as => :pet_state_swf_assets get '/species/:species_id/color/:color_id/pet_type.json' => 'pet_types#show' resources :contributions, :only => [:index] resources :items, :only => [:index, :show] do + resources :appearances, controller: 'item_appearances', only: [:index] collection do get :needed end end resources :outfits, :only => [:show, :create, :update, :destroy] resources :pet_attributes, :only => [:index] - resources :swf_assets, :only => [:index, :show] do + resources :swf_assets, :only => [:show] do collection do get :links end