From 7c6e6076122cf665e813c95ef9ed2295a1164910 Mon Sep 17 00:00:00 2001 From: Matchu Date: Sun, 8 Dec 2013 22:59:36 -0600 Subject: [PATCH] basic neopia api integration --- app/assets/javascripts/outfits/edit.js | 7 +++- app/assets/javascripts/wardrobe.js | 48 ++++++++++++++++++++++- app/controllers/application_controller.rb | 4 ++ app/controllers/pets_controller.rb | 30 ++++++++++---- app/helpers/outfits_helper.rb | 4 ++ app/models/item.rb | 4 +- app/models/pet.rb | 48 +++++++++++++---------- app/models/pet_state.rb | 12 +++++- app/views/outfits/new.html.haml | 16 ++++---- config/initializers/neopia.rb | 5 +++ config/routes.rb | 1 + 11 files changed, 138 insertions(+), 41 deletions(-) create mode 100644 config/initializers/neopia.rb diff --git a/app/assets/javascripts/outfits/edit.js b/app/assets/javascripts/outfits/edit.js index 7640de7e..c9f26172 100644 --- a/app/assets/javascripts/outfits/edit.js +++ b/app/assets/javascripts/outfits/edit.js @@ -211,6 +211,7 @@ View.Hash = function (wardrobe) { STRING: 2, INTEGER_ARRAY: 3 }, KEYS = { + biologies: TYPES.INTEGER_ARRAY, closet: TYPES.INTEGER_ARRAY, color: TYPES.INTEGER, name: TYPES.STRING, @@ -252,6 +253,9 @@ View.Hash = function (wardrobe) { } } + if(new_data.biologies) { + wardrobe.outfits.setPetStateAssetsByIds(new_data.biologies); + } if(new_data.color !== data.color || new_data.species !== data.species) { wardrobe.outfits.setPetTypeByColorAndSpecies(new_data.color, new_data.species); } @@ -372,7 +376,7 @@ View.Hash = function (wardrobe) { singleOutfitResponse('updatePetState', function (pet_state) { var pet_type = wardrobe.outfits.getPetType(); if(pet_state.id != data.state && pet_type && (data.state || pet_state.id != pet_type.pet_states[0].id)) { - changeQuery({state: pet_state.id}); + changeQuery({biologies: undefined, state: pet_state.id}); } }); @@ -384,6 +388,7 @@ View.Hash = function (wardrobe) { wardrobe.outfits.bind('loadOutfit', function (outfit) { changeQuery({ + biologies: undefined, closet: outfit.getClosetItemIds(), color: outfit.pet_type.color_id, objects: outfit.getWornItemIds(), diff --git a/app/assets/javascripts/wardrobe.js b/app/assets/javascripts/wardrobe.js index b005f8df..b6a159d7 100644 --- a/app/assets/javascripts/wardrobe.js +++ b/app/assets/javascripts/wardrobe.js @@ -476,9 +476,26 @@ function Wardrobe() { } } + this.setPetStateAssetsByIds = function (assetIds, petStateOnLoad) { + this.pet_state = PetState.createFromAssetIds(assetIds); + this.pet_state.loadAssets(petStateOnLoad); + } + this.setPetStateById = function (id, petStateOnLoad) { if(!id && this.pet_type) { - id = this.pet_type.pet_states[0].id; + if(this.pet_state) { + var candidate; + for(var i = 0; i < this.pet_type.pet_states.length; i++) { + candidate = this.pet_type.pet_states[i]; + if(arraysMatch(this.pet_state.assetIds, candidate.assetIds)) { + id = candidate.id; + break; + } + } + } + if(!id) { + id = this.pet_type.pet_states[0].id; + } } if(id) { this.pet_state = PetState.find(id); @@ -712,6 +729,7 @@ function Wardrobe() { this.id = id; this.gender_mood_description = ''; + this.assetIds = []; this.assets = []; this.loadAssets = function (success) { @@ -722,6 +740,9 @@ function Wardrobe() { $.getJSON('/pet_states/' + pet_state.id + '/swf_assets.json', function (data) { pet_state.assets = $.map(data, function (obj) { return new BiologyAsset(obj) }); + pet_state.assetIds = $.map(pet_state.assets, function (asset) { + return asset.id; + }); loaded = true; success(pet_state); }); @@ -730,11 +751,32 @@ function Wardrobe() { this.update = function (data) { this.gender_mood_description = data.gender_mood_description; + this.assetIds = data.swf_asset_ids; } PetState.cache[id] = this; } + PetState.createFromAssetIds = function (assetIds) { + // Fun lame hacks to be able to create from biology asset IDs. Not even a + // real PetState, gasp! + assetIds.sort(); + var petState = { + id: null, + gender_mood_description: '', + assets: [], + assetIds: assetIds, + loadAssets: function (success) { + $.getJSON('/swf_assets.json', {ids: {biology: assetIds}}, function (data) { + this.assets = $.map(data, function (obj) { return new BiologyAsset(obj) }); + success(petState); + }); + }, + update: $.noop + }; + return petState; + } + PetState.find = function (id) { var pet_state = PetState.cache[id]; if(!pet_state) { @@ -1001,6 +1043,10 @@ function Wardrobe() { } } + this.setPetStateAssetsByIds = function (assetIds) { + outfit.setPetStateAssetsByIds(assetIds, controller.event('updatePetState')); + } + this.setPetStateById = function (pet_state_id) { outfit.setPetStateById(pet_state_id, controller.event('updatePetState')); } diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index c864a706..0e49ffee 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -26,6 +26,10 @@ class ApplicationController < ActionController::Base http_accept_language.language_region_compatible_from(I18n.public_locales.map(&:to_s)) || I18n.default_locale end + + def local_only + raise AccessDenied unless request.ip == '127.0.0.1' + end def localized_fragment_exist?(key) localized_key = localize_fragment_key(key, locale) diff --git a/app/controllers/pets_controller.rb b/app/controllers/pets_controller.rb index 686eb211..01fb67d5 100644 --- a/app/controllers/pets_controller.rb +++ b/app/controllers/pets_controller.rb @@ -2,6 +2,9 @@ class PetsController < ApplicationController rescue_from Pet::PetNotFound, :with => :pet_not_found rescue_from PetType::DownloadError, SwfAsset::DownloadError, :with => :asset_download_error rescue_from Pet::DownloadError, :with => :pet_download_error + + protect_from_forgery except: :submit + before_filter :local_only, only: :submit cache_sweeper :user_sweeper @@ -11,14 +14,7 @@ class PetsController < ApplicationController else raise Pet::PetNotFound unless params[:name] @pet = Pet.load(params[:name], :item_scope => Item.includes(:translations)) - if user_signed_in? - points = current_user.contribute! @pet - else - @pet.save - points = true - end - - @pet.translate_items + points = contribute(current_user, @pet) respond_to do |format| format.html do @@ -32,8 +28,26 @@ class PetsController < ApplicationController end end end + + def submit + viewer_data = HashWithIndifferentAccess.new(JSON.parse(params[:viewer_data])) + @pet = Pet.from_viewer_data(viewer_data, :item_scope => Item.includes(:translations)) + @user = params[:user_id].present? ? User.find(params[:user_id]) : nil + render json: {points: contribute(@user, @pet)} + end protected + + def contribute(user, pet) + if user.present? + points = user.contribute! pet + else + pet.save! + points = true + end + pet.translate_items + points + end def destination case (params[:destination] || params[:origin]) diff --git a/app/helpers/outfits_helper.rb b/app/helpers/outfits_helper.rb index 06220510..cae91f76 100644 --- a/app/helpers/outfits_helper.rb +++ b/app/helpers/outfits_helper.rb @@ -49,6 +49,10 @@ module OutfitsHelper content_tag(:dt, search_query_with_helper(base, filter_key)) + content_tag(:dd, search_query_description(base, filter_key)) end + + def remote_load_pet_path + "http://#{Rails.configuration.neopia_host}/api/1/pet/customization" + end def outfit_creation_summary(outfit) user = outfit.user diff --git a/app/models/item.rb b/app/models/item.rb index 763a0418..00fa89e7 100644 --- a/app/models/item.rb +++ b/app/models/item.rb @@ -272,8 +272,10 @@ class Item < ActiveRecord::Base end def origin_registry_info=(info) + Rails.logger.debug("info! #{info}") # bear in mind that numbers from registries are floats - self.species_support_ids = info[:species_support].map(&:to_i) + species_support_strs = info['species_support'] || [] + self.species_support_ids = species_support_strs.map(&:to_i) attribute_names.each do |attribute| value = info[attribute.to_sym] if value diff --git a/app/models/pet.rb b/app/models/pet.rb index c93e95cf..5c90ccdf 100644 --- a/app/models/pet.rb +++ b/app/models/pet.rb @@ -18,30 +18,32 @@ class Pet < ActiveRecord::Base } def load!(options={}) - options[:item_scope] ||= Item.scoped options[:locale] ||= I18n.default_locale - - I18n.with_locale(options[:locale]) do - viewer_data = fetch_viewer_data(options[:timeout]) - pet_data = viewer_data[:custom_pet] - - self.pet_type = PetType.find_or_initialize_by_species_id_and_color_id( - pet_data[:species_id].to_i, - pet_data[:color_id].to_i - ) - self.pet_type.body_id = pet_data[:body_id] - self.pet_type.origin_pet = self - biology = pet_data[:biology_by_zone] - biology[0] = nil # remove effects if present - @pet_state = self.pet_type.add_pet_state_from_biology! biology - @pet_state.label_by_pet(self, pet_data[:owner]) - @items = Item.collection_from_pet_type_and_registries(self.pet_type, - viewer_data[:object_info_registry], viewer_data[:object_asset_registry], - options[:item_scope]) + I18n.with_locale(options.delete(:locale)) do + use_viewer_data(fetch_viewer_data(options.delete(:timeout)), options) end - true end + + def use_viewer_data(viewer_data, options={}) + options[:item_scope] ||= Item.scoped + + pet_data = viewer_data[:custom_pet] + + self.pet_type = PetType.find_or_initialize_by_species_id_and_color_id( + pet_data[:species_id].to_i, + pet_data[:color_id].to_i + ) + self.pet_type.body_id = pet_data[:body_id] + self.pet_type.origin_pet = self + biology = pet_data[:biology_by_zone] + biology[0] = nil # remove effects if present + @pet_state = self.pet_type.add_pet_state_from_biology! biology + @pet_state.label_by_pet(self, pet_data[:owner]) + @items = Item.collection_from_pet_type_and_registries(self.pet_type, + viewer_data[:object_info_registry], viewer_data[:object_asset_registry], + options[:item_scope]) + end def fetch_viewer_data(timeout=4) begin @@ -170,6 +172,12 @@ class Pet < ActiveRecord::Base pet end + def self.from_viewer_data(viewer_data, options={}) + pet = Pet.find_or_initialize_by_name(viewer_data[:custom_pet][:name]) + pet.use_viewer_data(viewer_data, options) + pet + end + class PetNotFound < Exception;end class DownloadError < Exception;end end diff --git a/app/models/pet_state.rb b/app/models/pet_state.rb index 4af03079..2c1c5859 100644 --- a/app/models/pet_state.rb +++ b/app/models/pet_state.rb @@ -38,7 +38,11 @@ class PetState < ActiveRecord::Base order("glitched ASC, (mood_id = 1) DESC, COUNT(effect_assets.remote_id) ASC, COUNT(parents_swf_assets.swf_asset_id) DESC, female ASC, SUM(parents_swf_assets.swf_asset_id) ASC") def as_json(options={}) - serializable_hash :only => [:id], :methods => [:gender_mood_description] + { + id: id, + gender_mood_description: gender_mood_description, + swf_asset_ids: swf_asset_ids_array + } end def reassign_children_to!(main_pet_state) @@ -66,13 +70,17 @@ class PetState < ActiveRecord::Base end def sort_swf_asset_ids! - self.swf_asset_ids = swf_asset_ids.split(',').map(&:to_i).sort.join(',') + self.swf_asset_ids = swf_asset_ids_array.sort.join(',') end def swf_asset_ids self['swf_asset_ids'] end + def swf_asset_ids_array + swf_asset_ids.split(',').map(&:to_i) + end + def swf_asset_ids=(ids) self['swf_asset_ids'] = ids end diff --git a/app/views/outfits/new.html.haml b/app/views/outfits/new.html.haml index f5b2dcad..d22fdc89 100644 --- a/app/views/outfits/new.html.haml +++ b/app/views/outfits/new.html.haml @@ -10,18 +10,18 @@ %h1= t 'app_name' %h2= t '.tagline' - = form_tag load_pet_path, :id => 'load-pet-to-wardrobe' do - - localized_cache :action_suffix => 'main_load_pet_form_content' do - = origin_tag root_path - = destination_tag 'wardrobe' + = form_tag remote_load_pet_path, method: 'GET', id: 'load-pet-to-wardrobe' do + = hidden_field_tag 'impress_user', current_user.try(:id) + - localized_cache action_suffix: 'outfits#new main_load_pet_form_content' do + = hidden_field_tag 'redirect', "#{wardrobe_url}\#{q}" %fieldset %legend= t '.load_pet.legend' = pet_name_tag :id => 'main-pet-name' %button{:type => "submit"} = t '.load_pet.submit' - = form_tag wardrobe_path, :method => 'get', :id => 'start-from-scratch' do - - localized_cache :action_suffix => 'start_from_scratch_form_content' do + - localized_cache action_suffix: 'outfits#new start_from_scratch_form' do + = form_tag wardrobe_path, method: 'GET', id: 'start-from-scratch', authenticity_token: false do %fieldset %legend= t '.start_from_scratch.legend' = pet_attribute_select 'color', @colors, 8 @@ -60,8 +60,8 @@ %div %h4= t '.modeling_hub.tagline' %p= t '.modeling_hub.description' - = form_tag load_pet_path do - = origin_tag root_path + = form_tag remote_load_pet_path, method: 'GET' do + = hidden_field_tag 'redirect', "#{root_url}\#{q}" = pet_name_tag :placeholder => t('.modeling_hub.load_pet.placeholder') = submit_tag t('.modeling_hub.load_pet.submit') diff --git a/config/initializers/neopia.rb b/config/initializers/neopia.rb new file mode 100644 index 00000000..5afcf3f4 --- /dev/null +++ b/config/initializers/neopia.rb @@ -0,0 +1,5 @@ +if Rails.env.production? + Rails.configuration.neopia_host = 'neopia.openneo.net' +else + Rails.configuration.neopia_host = 'localhost:3200' +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 437b24e5..d794e900 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -49,6 +49,7 @@ OpenneoImpressItems::Application.routes.draw do match '/users/current-user/outfits' => 'outfits#index', :as => :current_user_outfits match '/pets/load' => 'pets#load', :method => :post, :as => :load_pet + match '/pets/submit' => 'pets#submit', :method => :post match '/modeling' => 'pets#bulk', :as => :bulk_pets match '/login' => 'sessions#new', :as => :login