Compare commits

...

5 commits

Author SHA1 Message Date
f0257ba2d3 Merge branch 'main' into rainbow-pool 2024-09-27 18:32:04 -07:00
d056a5e766 Oops, don't show not-directly-for-sale items as being "0 NC"
"Fall Woodland Leaves Filter" is an example, it's part of the two-item
*pack* named "Fall Woodland Minitheus Petpet Foreground". The NC Mall
page for it will include the secondary items in `object_data`, but it's
not part of the storefront itself—and the only thing indicating that is
the `render` list.

Theoretically, we could use this to construct more data about like,
packs and stuff, automatically? But also, I don't want to backfill it
for everything historically, so like. Whatever.
2024-09-27 18:27:12 -07:00
5214a14990 Rescue from ActiveRecord::ConnectionTimeoutError
Just to stop filling the crash logs with it… if they spike, we'll be
alerted by the downtime monitor anyway.
2024-09-27 17:50:35 -07:00
06a89689d8 Oops, fix crash when modeling Patchwork Staff (AMFPHP string encoding!)
See comment for details! I wonder if other items have been affected by
this in the past. I think probably what happened before was that we
successfully created this item, but failed to create the *translation*,
so when migrating over the Patchwork Staff all its translated fields
were empty? (That's what I found looking in the database today.)

But yeah, thankfully our crash logging at health.openneo.net gave me
the name of a pet someone was trying to model, and so I was able to
find the bug and fix it!
2024-09-27 15:18:43 -07:00
a08fb89d59 Oops, don't crash when an item has no previews
A weird state to get into, one would expect impossible! But something
funny is going on with the Kiko Lake Team Popcorn item (85598)!
2024-09-27 15:18:43 -07:00
6 changed files with 111 additions and 6 deletions

View file

@ -21,9 +21,12 @@ class ApplicationController < ActionController::Base
class AccessDenied < StandardError; end
rescue_from AccessDenied, with: :on_access_denied
rescue_from Async::Stop, Async::Container::Terminate,
with: :on_request_stopped
rescue_from ActiveRecord::ConnectionTimeoutError, with: :on_db_timeout
def authenticate_user!
redirect_to(new_auth_user_session_path) unless user_signed_in?
end
@ -65,6 +68,11 @@ class ApplicationController < ActionController::Base
status: :internal_server_error
end
def on_db_timeout
render file: 'public/503.html', layout: false,
status: :service_unavailable
end
def redirect_back!(default=:back)
redirect_to(params[:return_to] || default)
end

View file

@ -215,7 +215,8 @@ class ItemsController < ApplicationController
@item.compatible_pet_types.
preferring_species(cookies["preferred-preview-species-id"] || "<ignore>").
preferring_color(cookies["preferred-preview-color-id"] || "<ignore>").
preferring_simple.first
preferring_simple.first ||
PetType.matching_name("Blue", "Acara").first!
end
def validate_preview

View file

@ -168,7 +168,7 @@ class Pet < ApplicationRecord
# Return the response body as a `HashWithIndifferentAccess`.
def self.send_amfphp_request(request, timeout: 10)
begin
response = request.post(timeout: timeout, headers: {
response_data = request.post(timeout: timeout, headers: {
"User-Agent" => Rails.configuration.user_agent_for_neopets,
})
rescue RocketAMFExtensions::RemoteGateway::AMFError => e
@ -177,7 +177,7 @@ class Pet < ApplicationRecord
raise DownloadError, e.message, e.backtrace
end
HashWithIndifferentAccess.new(response.messages[0].data.body)
HashWithIndifferentAccess.new(response_data)
end
end

View file

@ -76,11 +76,20 @@ module NCMall
raise UnexpectedResponseFormat, "missing field object_data in NC page"
end
object_data = nc_page["object_data"]
# NOTE: When there's no object data, it will be an empty array instead of
# an empty hash. Weird API thing to work around!
nc_page["object_data"] = {} if nc_page["object_data"] == []
object_data = {} if object_data == []
items = nc_page["object_data"].values.map do |item_info|
# Only the items in the `render` list are actually listed as directly for
# sale in the shop. `object_data` might contain other items that provide
# supporting information about them, but aren't actually for sale.
visible_object_data = (nc_page["render"] || []).
map { |id| object_data[id.to_s] }.
filter(&:present?)
items = visible_object_data.map do |item_info|
{
id: item_info["id"],
name: item_info["name"],

View file

@ -54,7 +54,25 @@ module RocketAMFExtensions
raise RocketAMF::AMFError.new(first_message_data)
end
result
# HACK: It seems to me that these messages come back with Windows-1250
# (or similar) encoding on the strings? I'm basing this on the
# Patchwork Staff item, whose description arrives as:
#
# "That staff is cute, but dont use it as a walking stick \x96 I " +
# "dont think it will hold you up!"
#
# And the `\x96` is meant to represent an endash, which it doesn't in
# UTF-8 or in most extended ASCII encodings, but *does* in Windows's
# specific extended ASCII.
#
# Idk if this is something to do with the AMFPHP spec or how the AMFPHP
# server code they use serializes strings (I couldn't find any
# reference to it?), or just their internal database encoding being
# passed along as-is, or what? But this seems to be the most correct
# interpretation I know how to do, so, let's do it!
result.messages[0].data.body.tap do |body|
reencode_strings! body, "Windows-1250", "UTF-8"
end
end
private
@ -86,6 +104,16 @@ module RocketAMFExtensions
raise ConnectionError, e.message
end
end
def reencode_strings!(target, from, to)
if target.is_a? String
target.force_encoding(from).encode!(to)
elsif target.is_a? Array
target.each { |x| reencode_strings!(x, from, to) }
elsif target.is_a? Hash
target.values.each { |x| reencode_strings!(x, from, to) }
end
end
end
class ConnectionError < RuntimeError

59
public/503.html Normal file
View file

@ -0,0 +1,59 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Dress to Impress: Whelmy mode!</title>
<style type="text/css">
body {
background-color: #fff;
color: #666;
font-family: arial, sans-serif;
padding: 2em 1em;
}
main {
border: 1px solid #ccc;
margin-inline: auto;
padding: 1em;
max-width: 600px;
display: grid;
grid-template-areas: "illustration body";
grid-template-columns: auto 1fr;
column-gap: 1em;
}
h1 {
font-size: 1.5em;
margin: 0;
margin-bottom: 0.5em;
}
p {
margin-bottom: 0.5em;
}
</style>
</head>
<body>
<main>
<img
width="100"
height="100"
alt="Distressed Grundo programmer"
src="/images/error-grundo.png"
/>
<div>
<h1>DTI is overloaded!</h1>
<p>
There's a lot going on in our server right now… usually this lasts for
a few seconds, then passes? Sorry about this!
</p>
<p>
If this keeps happening, we'll be alerted automatically, and we'll do
our best to get it fixed up 💖
</p>
</div>
</main>
</body>
</html>