2010-05-15 10:47:46 -07:00
|
|
|
class ItemsController < ApplicationController
|
2023-08-02 16:05:02 -07:00
|
|
|
before_action :set_query
|
2024-11-20 12:07:25 -08:00
|
|
|
before_action :support_staff_only, except: [:index, :show, :sources]
|
2013-01-21 11:44:02 -08:00
|
|
|
rescue_from Item::Search::Error, :with => :search_error
|
2011-05-20 17:23:37 -07:00
|
|
|
|
2010-05-15 10:47:46 -07:00
|
|
|
def index
|
2014-02-26 21:55:14 -08:00
|
|
|
if @query
|
2024-02-27 14:47:02 -08:00
|
|
|
if params[:per_page]
|
|
|
|
per_page = params[:per_page].to_i
|
|
|
|
per_page = 50 if per_page && per_page > 50
|
|
|
|
else
|
|
|
|
per_page = 30
|
|
|
|
end
|
2024-02-23 10:44:50 -08:00
|
|
|
|
2024-02-27 14:47:02 -08:00
|
|
|
@items = @query.results.paginate(
|
|
|
|
page: params[:page], per_page: per_page)
|
2024-06-16 12:37:53 -07:00
|
|
|
assign_closeted!(@items)
|
2024-02-23 10:44:50 -08:00
|
|
|
|
2024-02-27 14:47:02 -08:00
|
|
|
respond_to do |format|
|
|
|
|
format.html {
|
|
|
|
@campaign = Fundraising::Campaign.current rescue nil
|
|
|
|
if @items.count == 1
|
|
|
|
redirect_to @items.first
|
|
|
|
else
|
|
|
|
render
|
|
|
|
end
|
|
|
|
}
|
|
|
|
format.json {
|
|
|
|
render json: {
|
|
|
|
items: @items.as_json(
|
|
|
|
methods: [:nc?, :pb?, :owned?, :wanted?],
|
2024-09-08 18:15:27 -07:00
|
|
|
include: {
|
|
|
|
restricted_zones: {
|
|
|
|
only: [:id, :depth, :label],
|
|
|
|
methods: [:is_commonly_used_by_items],
|
|
|
|
},
|
|
|
|
},
|
2024-02-27 14:47:02 -08:00
|
|
|
),
|
|
|
|
appearances: load_appearances.as_json(
|
|
|
|
include: {
|
|
|
|
swf_assets: {
|
|
|
|
only: [:id, :remote_id, :body_id],
|
|
|
|
include: {
|
|
|
|
zone: {
|
|
|
|
only: [:id, :depth, :label],
|
|
|
|
methods: [:is_commonly_used_by_items],
|
|
|
|
},
|
|
|
|
restricted_zones: {
|
|
|
|
only: [:id, :depth, :label],
|
|
|
|
methods: [:is_commonly_used_by_items],
|
2024-02-25 12:06:20 -08:00
|
|
|
},
|
|
|
|
},
|
2024-02-27 14:47:02 -08:00
|
|
|
methods: [:urls, :known_glitches],
|
|
|
|
},
|
|
|
|
}
|
|
|
|
),
|
|
|
|
total_pages: @items.total_pages,
|
|
|
|
query: @query.to_s,
|
2013-06-26 23:01:12 -07:00
|
|
|
}
|
2024-02-27 14:47:02 -08:00
|
|
|
}
|
2010-05-15 10:47:46 -07:00
|
|
|
end
|
2010-10-10 19:18:42 -07:00
|
|
|
elsif params.has_key?(:ids) && params[:ids].is_a?(Array)
|
2023-08-02 11:41:19 -07:00
|
|
|
@items = Item.find(params[:ids])
|
2024-06-16 12:37:53 -07:00
|
|
|
assign_closeted!(@items)
|
2010-10-10 19:18:42 -07:00
|
|
|
respond_to do |format|
|
2013-06-26 23:01:12 -07:00
|
|
|
format.json { render json: @items }
|
2010-10-10 19:18:42 -07:00
|
|
|
end
|
2010-06-26 13:20:51 -07:00
|
|
|
else
|
|
|
|
respond_to do |format|
|
2011-08-04 07:01:44 -07:00
|
|
|
format.html {
|
2024-02-18 20:29:31 -08:00
|
|
|
@campaign = Fundraising::Campaign.current rescue nil
|
2024-02-20 16:04:41 -08:00
|
|
|
@newest_items = Item.newest.limit(18)
|
2011-08-04 07:01:44 -07:00
|
|
|
}
|
2010-06-26 13:20:51 -07:00
|
|
|
end
|
2010-05-15 10:47:46 -07:00
|
|
|
end
|
|
|
|
end
|
2011-05-20 17:23:37 -07:00
|
|
|
|
2010-05-15 17:46:41 -07:00
|
|
|
def show
|
|
|
|
@item = Item.find params[:id]
|
2011-07-30 21:19:28 -07:00
|
|
|
|
2011-08-02 17:01:48 -07:00
|
|
|
respond_to do |format|
|
|
|
|
format.html do
|
2024-01-21 04:49:06 -08:00
|
|
|
@trades = @item.closet_hangers.trading.user_is_active.to_trades
|
2024-01-19 01:39:25 -08:00
|
|
|
|
2024-01-21 00:39:20 -08:00
|
|
|
@contributors_with_counts = @item.contributors_with_counts
|
2011-08-02 17:01:48 -07:00
|
|
|
|
|
|
|
if user_signed_in?
|
2024-01-21 06:42:24 -08:00
|
|
|
@current_user_lists = current_user.closet_lists.alphabetical.
|
|
|
|
group_by_owned
|
|
|
|
@current_user_quantities = current_user.item_quantities_for(@item)
|
2011-08-02 17:01:48 -07:00
|
|
|
end
|
2024-06-30 23:09:28 -07:00
|
|
|
|
2024-06-30 23:34:27 -07:00
|
|
|
@selected_preview_pet_type = load_selected_preview_pet_type
|
2024-07-01 16:07:25 -07:00
|
|
|
@preview_outfit = Outfit.new(
|
|
|
|
pet_state: load_preview_pet_type.canonical_pet_state,
|
|
|
|
worn_items: [@item],
|
|
|
|
)
|
2024-06-30 23:34:27 -07:00
|
|
|
@preview_error = validate_preview
|
2024-09-03 12:55:10 -07:00
|
|
|
|
|
|
|
@all_appearances = @item.appearances
|
|
|
|
@appearances_by_occupied_zone = @item.appearances_by_occupied_zone.
|
|
|
|
sort_by { |z, a| z.label }
|
2024-09-05 18:48:41 -07:00
|
|
|
@selected_item_appearance = @preview_outfit.item_appearances.first
|
2024-09-03 13:23:58 -07:00
|
|
|
|
|
|
|
@preview_pet_type_options = PetType.where(color: @preview_outfit.color).
|
2024-09-05 17:39:47 -07:00
|
|
|
includes(:species).merge(Species.alphabetical)
|
2011-08-02 17:01:48 -07:00
|
|
|
end
|
|
|
|
|
|
|
|
format.gif do
|
|
|
|
expires_in 1.month
|
2024-03-12 18:45:05 -07:00
|
|
|
redirect_to @item.thumbnail_url, allow_other_host: true
|
2011-07-22 12:31:23 -07:00
|
|
|
end
|
2011-07-14 09:50:24 -07:00
|
|
|
end
|
2010-05-15 17:46:41 -07:00
|
|
|
end
|
2011-05-20 17:23:37 -07:00
|
|
|
|
2024-11-20 12:07:25 -08:00
|
|
|
def edit
|
|
|
|
@item = Item.find params[:id]
|
|
|
|
render layout: "application"
|
|
|
|
end
|
|
|
|
|
|
|
|
def update
|
|
|
|
@item = Item.find params[:id]
|
|
|
|
if @item.update(item_params)
|
|
|
|
flash[:notice] = "\"#{@item.name}\" successfully saved!"
|
|
|
|
redirect_to @item
|
|
|
|
else
|
2024-11-30 11:45:35 -08:00
|
|
|
render action: "edit", layout: "application", status: :bad_request
|
2024-11-20 12:07:25 -08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
Add bare-bones Item Getting Guide page
TNT requested that we figure out ways to connect the dots between
people's intentions on DTI to their purchases in the NC Mall.
But rather than just slam ad links everywhere, our plan is to design an
actually useful feature about it: the "Item Getting Guide". It'll break
down items by how you can actually get them (NP economy, NC Mall,
retired NC, Dyeworks, etc), and we're planning some cute actions you
can take, like shortcuts for getting them onto trade wishlists or into
your NC Mall cart.
This is just a little demo version of the page, just breaking down
items specified in the URL into NC/NP/PB! Later we'll do more granular
breakdown than this, with more info and actions—and we'll also like,
link to it at all, which isn't the case yet! (The main way we expect
people to get here is by a "Get these items" button we'll add to the
outfit editor, but there might be other paths, too.)
2024-05-06 20:37:59 -07:00
|
|
|
def sources
|
2024-06-16 12:37:53 -07:00
|
|
|
# Load all the items, then group them by source.
|
Add bare-bones Item Getting Guide page
TNT requested that we figure out ways to connect the dots between
people's intentions on DTI to their purchases in the NC Mall.
But rather than just slam ad links everywhere, our plan is to design an
actually useful feature about it: the "Item Getting Guide". It'll break
down items by how you can actually get them (NP economy, NC Mall,
retired NC, Dyeworks, etc), and we're planning some cute actions you
can take, like shortcuts for getting them onto trade wishlists or into
your NC Mall cart.
This is just a little demo version of the page, just breaking down
items specified in the URL into NC/NP/PB! Later we'll do more granular
breakdown than this, with more info and actions—and we'll also like,
link to it at all, which isn't the case yet! (The main way we expect
people to get here is by a "Get these items" button we'll add to the
outfit editor, but there might be other paths, too.)
2024-05-06 20:37:59 -07:00
|
|
|
item_ids = params[:ids].split(",")
|
2024-06-16 12:37:53 -07:00
|
|
|
@all_items = Item.where(id: item_ids).includes(:nc_mall_record).
|
2024-06-09 13:25:59 -07:00
|
|
|
includes(:dyeworks_base_item).order(:name).limit(50)
|
2024-06-17 13:03:12 -07:00
|
|
|
@items = @all_items.group_by(&:source).tap { |i| i.default = [] }
|
Add bare-bones Item Getting Guide page
TNT requested that we figure out ways to connect the dots between
people's intentions on DTI to their purchases in the NC Mall.
But rather than just slam ad links everywhere, our plan is to design an
actually useful feature about it: the "Item Getting Guide". It'll break
down items by how you can actually get them (NP economy, NC Mall,
retired NC, Dyeworks, etc), and we're planning some cute actions you
can take, like shortcuts for getting them onto trade wishlists or into
your NC Mall cart.
This is just a little demo version of the page, just breaking down
items specified in the URL into NC/NP/PB! Later we'll do more granular
breakdown than this, with more info and actions—and we'll also like,
link to it at all, which isn't the case yet! (The main way we expect
people to get here is by a "Get these items" button we'll add to the
outfit editor, but there might be other paths, too.)
2024-05-06 20:37:59 -07:00
|
|
|
|
2024-06-16 12:37:53 -07:00
|
|
|
assign_closeted!(@all_items)
|
|
|
|
|
|
|
|
if @all_items.empty?
|
Add bare-bones Item Getting Guide page
TNT requested that we figure out ways to connect the dots between
people's intentions on DTI to their purchases in the NC Mall.
But rather than just slam ad links everywhere, our plan is to design an
actually useful feature about it: the "Item Getting Guide". It'll break
down items by how you can actually get them (NP economy, NC Mall,
retired NC, Dyeworks, etc), and we're planning some cute actions you
can take, like shortcuts for getting them onto trade wishlists or into
your NC Mall cart.
This is just a little demo version of the page, just breaking down
items specified in the URL into NC/NP/PB! Later we'll do more granular
breakdown than this, with more info and actions—and we'll also like,
link to it at all, which isn't the case yet! (The main way we expect
people to get here is by a "Get these items" button we'll add to the
outfit editor, but there might be other paths, too.)
2024-05-06 20:37:59 -07:00
|
|
|
render file: "public/404.html", status: :not_found, layout: nil
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2024-06-09 14:46:24 -07:00
|
|
|
# For Dyeworks items whose base is currently in the NC Mall, preload their
|
|
|
|
# trade values. We'll use this to determine which ones are fully buyable rn
|
|
|
|
# (because Owls tracks this data and we don't).
|
2024-06-16 12:37:53 -07:00
|
|
|
Item.preload_nc_trade_values(@items[:dyeworks])
|
2024-05-22 17:53:52 -07:00
|
|
|
|
2024-05-27 16:21:22 -07:00
|
|
|
# Start loading the NC trade values for the non-Mall NC items.
|
2024-06-16 12:37:53 -07:00
|
|
|
trade_values_task = Async { Item.preload_nc_trade_values(@items[:other_nc]) }
|
2024-05-27 16:21:22 -07:00
|
|
|
|
2024-05-22 17:53:52 -07:00
|
|
|
# Also, PB items have some special handling: we group them by color, then
|
|
|
|
# load example pet types for the colors that don't have paint brushes.
|
2024-06-16 12:37:53 -07:00
|
|
|
@pb_items_by_color = @items[:pb].group_by(&:pb_color).
|
Handle newly-released PB items in Item Getting Guide
Oh right, it's possible for `Item#pb?` to return true, but
`Item#pb_color` to return `nil`, if the item has the paintbrush item
description but we can't find a color whose name matches the item name.
This would be expected if a new color were added to Neopets, and PB
items for it were modeled by the community, but we hadn't manually
added the color to the database yet.
Previously, the Item Getting Guide would crash in this scenario. Now,
it correctly handles the possibility of a `nil` value for `pb_color`,
and shows some placeholder info.
To test this, I temporarily edited some item names to not contain the
color name anymore (e.g. "P-rate Elephante Shirt and Vest"), then
loaded the guide and made changes until it no longer crashed.
2024-06-05 19:20:57 -07:00
|
|
|
sort_by { |color, items| color&.name }.to_h
|
Add bare-bones Item Getting Guide page
TNT requested that we figure out ways to connect the dots between
people's intentions on DTI to their purchases in the NC Mall.
But rather than just slam ad links everywhere, our plan is to design an
actually useful feature about it: the "Item Getting Guide". It'll break
down items by how you can actually get them (NP economy, NC Mall,
retired NC, Dyeworks, etc), and we're planning some cute actions you
can take, like shortcuts for getting them onto trade wishlists or into
your NC Mall cart.
This is just a little demo version of the page, just breaking down
items specified in the URL into NC/NP/PB! Later we'll do more granular
breakdown than this, with more info and actions—and we'll also like,
link to it at all, which isn't the case yet! (The main way we expect
people to get here is by a "Get these items" button we'll add to the
outfit editor, but there might be other paths, too.)
2024-05-06 20:37:59 -07:00
|
|
|
|
Handle newly-released PB items in Item Getting Guide
Oh right, it's possible for `Item#pb?` to return true, but
`Item#pb_color` to return `nil`, if the item has the paintbrush item
description but we can't find a color whose name matches the item name.
This would be expected if a new color were added to Neopets, and PB
items for it were modeled by the community, but we hadn't manually
added the color to the database yet.
Previously, the Item Getting Guide would crash in this scenario. Now,
it correctly handles the possibility of a `nil` value for `pb_color`,
and shows some placeholder info.
To test this, I temporarily edited some item names to not contain the
color name anymore (e.g. "P-rate Elephante Shirt and Vest"), then
loaded the guide and made changes until it no longer crashed.
2024-06-05 19:20:57 -07:00
|
|
|
colors_without_thumbnails = @pb_items_by_color.keys.
|
|
|
|
select(&:present?).reject(&:pb_item_thumbnail_url?)
|
2024-05-22 17:53:52 -07:00
|
|
|
|
|
|
|
@pb_color_pet_types = colors_without_thumbnails.map do |color|
|
|
|
|
# Infer the ideal species from the first item we can, then try to find a
|
|
|
|
# matching pet type to use as the thumbnail, if needed.
|
|
|
|
species = @pb_items_by_color[color].map(&:pb_species).select(&:present?)
|
|
|
|
.first
|
|
|
|
[color, color.example_pet_type(preferred_species: species)]
|
|
|
|
end.to_h
|
|
|
|
|
2024-06-15 15:47:52 -07:00
|
|
|
# Create a second value that only include the items the user *needs*: that
|
|
|
|
# is, that they don't already own.
|
2024-06-16 12:37:53 -07:00
|
|
|
@items_needed = @items.transform_values { |items| items.reject(&:owned?) }
|
2024-06-15 15:47:52 -07:00
|
|
|
@pb_items_needed_by_color =
|
|
|
|
@pb_items_by_color.transform_values { |items| items.reject(&:owned?) }
|
|
|
|
|
2024-05-27 16:21:22 -07:00
|
|
|
# Finish loading the NC trade values.
|
|
|
|
trade_values_task.wait
|
|
|
|
|
Add bare-bones Item Getting Guide page
TNT requested that we figure out ways to connect the dots between
people's intentions on DTI to their purchases in the NC Mall.
But rather than just slam ad links everywhere, our plan is to design an
actually useful feature about it: the "Item Getting Guide". It'll break
down items by how you can actually get them (NP economy, NC Mall,
retired NC, Dyeworks, etc), and we're planning some cute actions you
can take, like shortcuts for getting them onto trade wishlists or into
your NC Mall cart.
This is just a little demo version of the page, just breaking down
items specified in the URL into NC/NP/PB! Later we'll do more granular
breakdown than this, with more info and actions—and we'll also like,
link to it at all, which isn't the case yet! (The main way we expect
people to get here is by a "Get these items" button we'll add to the
outfit editor, but there might be other paths, too.)
2024-05-06 20:37:59 -07:00
|
|
|
render layout: "application"
|
|
|
|
end
|
|
|
|
|
2011-07-12 22:21:48 -07:00
|
|
|
protected
|
|
|
|
|
2024-11-20 12:07:25 -08:00
|
|
|
def item_params
|
|
|
|
params.require(:item).permit(
|
2024-11-20 12:13:33 -08:00
|
|
|
:name, :thumbnail_url, :description, :modeling_status_hint,
|
2024-11-20 12:23:30 -08:00
|
|
|
:is_manually_nc, :explicitly_body_specific,
|
2024-11-20 12:07:25 -08:00
|
|
|
).tap do |p|
|
|
|
|
p[:modeling_status_hint] = nil if p[:modeling_status_hint] == ""
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-06-16 12:37:53 -07:00
|
|
|
def assign_closeted!(items)
|
|
|
|
current_user.assign_closeted_to_items!(items) if user_signed_in?
|
2011-07-12 22:21:48 -07:00
|
|
|
end
|
2024-02-23 10:44:50 -08:00
|
|
|
|
|
|
|
def load_appearances
|
2024-02-25 14:46:27 -08:00
|
|
|
appearance_params = params[:with_appearances_for]
|
|
|
|
return {} if appearance_params.blank?
|
2024-02-27 16:11:06 -08:00
|
|
|
|
|
|
|
if appearance_params[:alt_style_id].present?
|
|
|
|
target = Item::Search::Query.load_alt_style_by_id(
|
|
|
|
appearance_params[:alt_style_id])
|
|
|
|
else
|
|
|
|
target = Item::Search::Query.load_pet_type_by_color_and_species(
|
|
|
|
appearance_params[:color_id], appearance_params[:species_id])
|
|
|
|
end
|
2024-02-23 10:44:50 -08:00
|
|
|
|
2024-07-01 16:54:39 -07:00
|
|
|
target.appearances_for(@items, swf_asset_includes: [:zone]).
|
2024-05-28 17:05:04 -07:00
|
|
|
tap do |appearances|
|
|
|
|
# Preload the manifests for these SWF assets concurrently, rather than
|
|
|
|
# loading them in sequence when we generate the JSON.
|
|
|
|
swf_assets = appearances.values.map(&:swf_assets).flatten
|
|
|
|
SwfAsset.preload_manifests(swf_assets)
|
|
|
|
end
|
2024-02-23 10:44:50 -08:00
|
|
|
end
|
2024-06-30 23:34:27 -07:00
|
|
|
|
|
|
|
def load_selected_preview_pet_type
|
|
|
|
color_id = params.dig(:preview, :color_id)
|
|
|
|
species_id = params.dig(:preview, :species_id)
|
|
|
|
|
|
|
|
return load_default_preview_pet_type if color_id.nil? || species_id.nil?
|
|
|
|
|
2024-07-01 17:38:31 -07:00
|
|
|
PetType.find_or_initialize_by(color_id:, species_id:).tap do |pet_type|
|
|
|
|
if pet_type.persisted?
|
|
|
|
cookies["preferred-preview-color-id"] = color_id
|
|
|
|
cookies["preferred-preview-species-id"] = species_id
|
|
|
|
end
|
|
|
|
end
|
2024-06-30 23:34:27 -07:00
|
|
|
end
|
|
|
|
|
|
|
|
def load_preview_pet_type
|
|
|
|
if @selected_preview_pet_type.persisted?
|
|
|
|
@selected_preview_pet_type
|
|
|
|
else
|
|
|
|
load_default_preview_pet_type
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def load_default_preview_pet_type
|
2024-07-01 17:38:31 -07:00
|
|
|
@item.compatible_pet_types.
|
|
|
|
preferring_species(cookies["preferred-preview-species-id"] || "<ignore>").
|
|
|
|
preferring_color(cookies["preferred-preview-color-id"] || "<ignore>").
|
2024-09-27 14:14:28 -07:00
|
|
|
preferring_simple.first ||
|
|
|
|
PetType.matching_name("Blue", "Acara").first!
|
2024-06-30 23:34:27 -07:00
|
|
|
end
|
|
|
|
|
|
|
|
def validate_preview
|
|
|
|
if @selected_preview_pet_type.new_record?
|
|
|
|
:pet_type_does_not_exist
|
2024-07-01 16:54:39 -07:00
|
|
|
elsif @preview_outfit.item_appearances.any?(&:empty?)
|
2024-06-30 23:34:27 -07:00
|
|
|
:no_item_data
|
|
|
|
end
|
|
|
|
end
|
2013-01-21 11:44:02 -08:00
|
|
|
|
|
|
|
def search_error(e)
|
|
|
|
@items = []
|
2024-02-27 14:47:57 -08:00
|
|
|
@query = params[:q]
|
2013-01-21 11:44:02 -08:00
|
|
|
respond_to do |format|
|
|
|
|
format.html { flash.now[:alert] = e.message; render }
|
2013-06-26 23:01:12 -07:00
|
|
|
format.json { render :json => {error: e.message} }
|
2013-01-21 11:44:02 -08:00
|
|
|
end
|
|
|
|
end
|
2011-05-20 17:23:37 -07:00
|
|
|
|
2010-06-07 17:02:46 -07:00
|
|
|
def set_query
|
2014-02-26 21:55:14 -08:00
|
|
|
q = params[:q]
|
|
|
|
if q.is_a?(String)
|
2024-02-27 14:47:57 -08:00
|
|
|
@query = Item::Search::Query.from_text(q, current_user)
|
2024-02-23 10:44:50 -08:00
|
|
|
elsif q.is_a?(ActionController::Parameters)
|
2014-02-26 21:55:14 -08:00
|
|
|
@query = Item::Search::Query.from_params(q, current_user)
|
|
|
|
end
|
2010-06-07 17:02:46 -07:00
|
|
|
end
|
2010-05-15 10:47:46 -07:00
|
|
|
end
|