Compare commits

..

No commits in common. "e511bdc5e2dca96c8daa4acd35aaac7a80a7d540" and "610177d3f5276ca675ac14ee678e586fd0dff274" have entirely different histories.

17 changed files with 59 additions and 179 deletions

View file

@ -11,8 +11,7 @@ class ContributionsController < ApplicationController
@contributions,
:scopes => {
'Item' => Item.includes(:translations),
'PetType' => PetType.includes(:species, :color),
'AltStyle' => AltStyle.includes(:species, :color),
'PetType' => PetType.includes(:species, :color)
}
)
end

View file

@ -1,13 +1,10 @@
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
rescue_from Pet::UnexpectedDataFormat, with: :unexpected_data_format
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
rescue_from Pet::ModelingDisabled, with: :modeling_disabled
def load
# Uncomment this to temporarily disable modeling for most users.
# return modeling_disabled unless user_signed_in? && current_user.admin?
raise Pet::PetNotFound unless params[:name]
@pet = Pet.load(
params[:name],
@ -83,9 +80,4 @@ class PetsController < ApplicationController
pet_load_error long_message: t('pets.load.modeling_disabled'),
status: :forbidden
end
def unexpected_data_format
pet_load_error long_message: t('pets.load.unexpected_data_format'),
status: :internal_server_error
end
end

View file

@ -9,8 +9,6 @@ module ContributionHelper
contributed_pet_type('pet_type', contributed, show_image)
when PetState
contributed_pet_type('pet_state', contributed.pet_type, show_image)
when AltStyle
contributed_alt_style(contributed, show_image)
end
end
@ -38,20 +36,6 @@ module ContributionHelper
output << image_tag(sprintf(PET_TYPE_IMAGE_FORMAT, pet_type.image_hash)) if show_image
output
end
def contributed_alt_style(alt_style, show_image)
span = content_tag(:span, alt_style.name, class: 'contributed-name')
output = translate("contributions.contributed_description.main.alt_style_html",
alt_style_name: span)
# HACK: Just assume this is a Nostalgic Alt Style, and that the thumbnail
# is named reliably!
if show_image
thumbnail_url = "https://images.neopets.com/items/nostalgic_" +
"#{alt_style.color.name.downcase}_#{alt_style.species.name.downcase}.gif"
output << image_tag(thumbnail_url)
end
output
end
private

View file

@ -1,22 +0,0 @@
class AltStyle < ApplicationRecord
belongs_to :species
belongs_to :color
has_many :parent_swf_asset_relationships, as: :parent
has_many :swf_assets, through: :parent_swf_asset_relationships
has_many :contributions, as: :contributed, inverse_of: :contributed
def name
I18n.translate('pet_types.human_name', color_human_name: color.human_name,
species_human_name: species.human_name)
end
def biology=(biology)
# TODO: This is very similar to what `PetState` does, but like… much much
# more compact? Idk if I'm missing something, or if I was just that much
# more clueless back when I wrote it, lol 😅
self.swf_assets = biology.values.map do |asset_data|
SwfAsset.from_biology_data(self.body_id, asset_data)
end
end
end

View file

@ -3,8 +3,7 @@ class Contribution < ApplicationRecord
'Item' => 3,
'SwfAsset' => 2,
'PetType' => 15,
'PetState' => 10,
'AltStyle' => 30,
'PetState' => 10
}
belongs_to :contributed, :polymorphic => true
@ -25,7 +24,7 @@ class Contribution < ApplicationRecord
'SwfAsset' => 'Item',
'PetState' => 'PetType'
}
CONTRIBUTED_CHILDREN = CONTRIBUTED_RELATIONSHIPS.keys + ['AltStyle']
CONTRIBUTED_CHILDREN = CONTRIBUTED_RELATIONSHIPS.keys
CONTRIBUTED_TYPES = CONTRIBUTED_CHILDREN + CONTRIBUTED_RELATIONSHIPS.values
def self.preload_contributeds_and_parents(contributions, options={})
options[:scopes] ||= {}

View file

@ -1,29 +1,28 @@
require 'rocketamf_extensions/remote_gateway'
require 'rocketamf/remote_gateway'
require 'ostruct'
class Pet < ApplicationRecord
NEOPETS_URL_ORIGIN = ENV['NEOPETS_URL_ORIGIN'] || 'https://www.neopets.com'
GATEWAY_URL = NEOPETS_URL_ORIGIN + '/amfphp/gateway.php'
PET_VIEWER = RocketAMFExtensions::RemoteGateway.new(GATEWAY_URL).
PET_VIEWER = RocketAMF::RemoteGateway.new(GATEWAY_URL).
service('CustomPetService').action('getViewerData')
PET_NOT_FOUND_REMOTE_ERROR = 'PHP: Unable to retrieve records from the database.'
WARDROBE_PATH = '/wardrobe'
belongs_to :pet_type
attr_reader :items, :pet_state, :alt_style
attr_reader :items, :pet_state
scope :with_pet_type_color_ids, ->(color_ids) {
joins(:pet_type).where(PetType.arel_table[:id].in(color_ids))
}
class ModelingDisabled < RuntimeError;end
def load!(options={})
raise ModelingDisabled
options[:locale] ||= I18n.default_locale
I18n.with_locale(options.delete(:locale)) do
use_viewer_data(
self.class.fetch_viewer_data(name, options.delete(:timeout)),
options,
)
use_viewer_data(fetch_viewer_data(options.delete(:timeout)), options)
end
true
end
@ -33,40 +32,43 @@ class Pet < ApplicationRecord
pet_data = viewer_data[:custom_pet]
raise UnexpectedDataFormat unless pet_data[:species_id]
raise UnexpectedDataFormat unless pet_data[:color_id]
raise UnexpectedDataFormat unless pet_data[:body_id]
self.pet_type = PetType.find_or_initialize_by(
species_id: pet_data[:species_id].to_i,
color_id: pet_data[:color_id].to_i
)
self.pet_type.body_id = pet_data[:body_id]
self.pet_type.origin_pet = self
pet_state_biology = pet_data[:alt_style] ?
pet_data[:original_biology] : pet_data[:biology_by_zone]
raise UnexpectedDataFormat if pet_state_biology.empty?
pet_state_biology[0] = nil # remove effects if present
@pet_state = self.pet_type.add_pet_state_from_biology! pet_state_biology
if pet_data[:alt_style]
raise UnexpectedDataFormat unless pet_data[:alt_color]
raise UnexpectedDataFormat if pet_data[:biology_by_zone].empty?
@alt_style = AltStyle.find_or_initialize_by(id: pet_data[:alt_style].to_i)
@alt_style.assign_attributes(
color_id: pet_data[:alt_color].to_i,
species_id: pet_data[:species_id].to_i,
body_id: pet_data[:body_id].to_i,
biology: pet_data[:biology_by_zone],
)
end
biology = pet_data[:biology_by_zone]
biology[0] = nil # remove effects if present
@pet_state = self.pet_type.add_pet_state_from_biology! biology
@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
# NOTE: Ideally pet requests shouldn't take this long, but Neopets can be
# slow sometimes! Since we're on the Falcon server, long timeouts shouldn't
# slow down the rest of the request queue, like it used to be in the past.
def fetch_viewer_data(timeout=10, locale=nil)
locale ||= I18n.default_locale
begin
neopets_language_code = I18n.compatible_neopets_language_code_for(locale)
envelope = PET_VIEWER.request([name, 0]).post(
:timeout => timeout,
:headers => {
'Cookie' => "lang=#{neopets_language_code}"
}
)
rescue RocketAMF::RemoteGateway::AMFError => e
if e.message == PET_NOT_FOUND_REMOTE_ERROR
raise PetNotFound, "Pet #{name.inspect} does not exist"
end
raise DownloadError, e.message
rescue RocketAMF::RemoteGateway::ConnectionError => e
raise DownloadError, e.message, e.backtrace
end
HashWithIndifferentAccess.new(envelope.messages[0].data.body)
end
def wardrobe_query
{
@ -79,7 +81,7 @@ class Pet < ApplicationRecord
end
def contributables
contributables = [pet_type, @pet_state, @alt_style].filter(&:present?)
contributables = [pet_type, @pet_state]
items.each do |item|
contributables << item
contributables += item.pending_swf_assets
@ -100,10 +102,6 @@ class Pet < ApplicationRecord
item.handle_assets!
end
end
if @alt_style
@alt_style.save!
end
end
def self.load(name, options={})
@ -118,32 +116,7 @@ class Pet < ApplicationRecord
pet
end
# NOTE: Ideally pet requests shouldn't take this long, but Neopets can be
# slow sometimes! Since we're on the Falcon server, long timeouts shouldn't
# slow down the rest of the request queue, like it used to be in the past.
def self.fetch_viewer_data(name, timeout=10, locale=nil)
locale ||= I18n.default_locale
begin
neopets_language_code = I18n.compatible_neopets_language_code_for(locale)
envelope = PET_VIEWER.request([name, 0]).post(
:timeout => timeout,
:headers => {
'Cookie' => "lang=#{neopets_language_code}"
}
)
rescue RocketAMFExtensions::RemoteGateway::AMFError => e
if e.message == PET_NOT_FOUND_REMOTE_ERROR
raise PetNotFound, "Pet #{name.inspect} does not exist"
end
raise DownloadError, e.message
rescue RocketAMFExtensions::RemoteGateway::ConnectionError => e
raise DownloadError, e.message, e.backtrace
end
HashWithIndifferentAccess.new(envelope.messages[0].data.body)
end
class PetNotFound < RuntimeError;end
class DownloadError < RuntimeError;end
class UnexpectedDataFormat < RuntimeError;end
class PetNotFound < Exception;end
class DownloadError < Exception;end
end

View file

@ -180,15 +180,6 @@ class SwfAsset < ApplicationRecord
self.manifest_url = parsed_manifest_url.to_s
end
def self.from_biology_data(body_id, data)
remote_id = data[:part_id].to_i
swf_asset = SwfAsset.find_or_initialize_by type: 'biology',
remote_id: remote_id
swf_asset.body_id = body_id
swf_asset.origin_biology_data = data
swf_asset
end
def self.from_wardrobe_link_params(ids)
where((
arel_table[:remote_id].in(ids[:biology]).and(arel_table[:type].eq('biology'))

View file

@ -2,12 +2,10 @@
= advertise_campaign_progress @campaign
.notice
.warning
%strong Happy NC UC day!
We're still working on Alt Styles support, but other pets can be loaded as
usual!
%br
Excited to have them for you soon!
We've temporarily disabled pet loading while we get everything set up and
investigate some new compatibility issues. We'll have it back soon!
%p#pet-not-found.alert= t 'pets.load.not_found'

View file

@ -12,7 +12,7 @@ Rack::Attack.throttled_responder = lambda do |req|
if req.path.end_with?('.json')
[503, {}, [PETS_THROTTLE_MESSAGE]]
else
flash = req.env['action_dispatch.request.flash_hash']
flash = req.flash
flash[:warning] = PETS_THROTTLE_MESSAGE
[302, {"Location" => "/"}, [PETS_THROTTLE_MESSAGE]]
end

View file

@ -232,7 +232,6 @@ en:
swf_asset_html: "%{item_description} on a new body type"
pet_type_html: "%{pet_type_description} for the first time"
pet_state_html: "a new pose for %{pet_type_description}"
alt_style_html: "a new Alt Style of the %{alt_style_name}"
contribution:
description_html: "%{user_link} showed us %{contributed_description}"
@ -785,10 +784,6 @@ en:
modeling_disabled: We've turned off pet loading for a bit, while we
investigate some changes in how it works. We'll be back as soon as we
can!
unexpected_data_format:
We found the pet and what it's wearing, but the data isn't in quite the
format we usually expect, so we're stopping to make sure we don't make
a mistake. Sorry about this—if it keeps happening, let us know!
swf_assets:
links:

View file

@ -1,11 +0,0 @@
class CreateAltStyles < ActiveRecord::Migration[7.1]
def change
create_table :alt_styles do |t|
t.references :species, type: :integer, null: false, foreign_key: true
t.references :color, type: :integer, null: false, foreign_key: true
t.integer :body_id, null: false
t.timestamps
end
end
end

View file

@ -10,17 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.1].define(version: 2024_01_24_102340) do
create_table "alt_styles", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t|
t.integer "species_id", null: false
t.integer "color_id", null: false
t.integer "body_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["color_id"], name: "index_alt_styles_on_color_id"
t.index ["species_id"], name: "index_alt_styles_on_species_id"
end
ActiveRecord::Schema[7.1].define(version: 2024_01_23_133215) do
create_table "auth_servers", id: :integer, charset: "latin1", collation: "latin1_swedish_ci", force: :cascade do |t|
t.string "short_name", limit: 10, null: false
t.string "name", limit: 40, null: false
@ -311,6 +301,4 @@ ActiveRecord::Schema[7.1].define(version: 2024_01_24_102340) do
t.string "plain_label", null: false
end
add_foreign_key "alt_styles", "colors"
add_foreign_key "alt_styles", "species"
end

View file

@ -1,8 +1,8 @@
require 'net/http'
require 'rocketamf'
require_relative 'remote_gateway/service'
require File.join(File.dirname(__FILE__), 'remote_gateway', 'service')
module RocketAMFExtensions
module RocketAMF
class RemoteGateway
attr_reader :uri

View file

@ -1,6 +1,6 @@
require_relative 'request'
require File.join(File.dirname(__FILE__), 'request')
module RocketAMFExtensions
module RocketAMF
class RemoteGateway
class Action
attr_reader :service, :name

View file

@ -1,6 +1,6 @@
require 'timeout'
module RocketAMFExtensions
module RocketAMF
class RemoteGateway
class Request
ERROR_CODE = 'AMFPHP_RUNTIME_ERROR'
@ -51,7 +51,7 @@ module RocketAMFExtensions
first_message_data = HashWithIndifferentAccess.new(result.messages[0].data)
if first_message_data.respond_to?(:[]) && first_message_data[:code] == ERROR_CODE
raise RocketAMF::AMFError.new(first_message_data)
raise AMFError.new(first_message_data)
end
result
@ -60,17 +60,17 @@ module RocketAMFExtensions
private
def envelope
output = RocketAMF::Envelope.new
output = Envelope.new
output.messages << wrapper_message
output
end
def wrapper_message
message = RocketAMF::Message.new 'null', '/1', [remoting_message]
message = Message.new 'null', '/1', [remoting_message]
end
def remoting_message
message = RocketAMF::Values::RemotingMessage.new
message = Values::RemotingMessage.new
message.source = @action.service.name
message.operation = @action.name
message.body = @params

View file

@ -1,6 +1,6 @@
require_relative 'action'
require File.join(File.dirname(__FILE__), 'action')
module RocketAMFExtensions
module RocketAMF
class RemoteGateway
class Service
attr_reader :gateway, :name

View file

@ -1,6 +0,0 @@
namespace :pets do
desc "Load a pet's viewer data"
task :load, [:name] => [:environment] do |task, args|
pp Pet.fetch_viewer_data(args[:name])
end
end