forked from OpenNeo/impress
Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
5401ea984a
6 changed files with 126 additions and 46 deletions
|
@ -3,6 +3,7 @@ require "async/barrier"
|
||||||
|
|
||||||
class Item < ApplicationRecord
|
class Item < ApplicationRecord
|
||||||
include PrettyParam
|
include PrettyParam
|
||||||
|
include Item::Dyeworks
|
||||||
|
|
||||||
# We use the `type` column to mean something other than what Rails means!
|
# We use the `type` column to mean something other than what Rails means!
|
||||||
self.inheritance_column = nil
|
self.inheritance_column = nil
|
||||||
|
@ -196,49 +197,6 @@ class Item < ApplicationRecord
|
||||||
nc_mall_record.present?
|
nc_mall_record.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def dyeworks?
|
|
||||||
dyeworks_base_item.present?
|
|
||||||
end
|
|
||||||
|
|
||||||
# Whether this is a Dyeworks item whose base item can currently be purchased
|
|
||||||
# in the NC Mall. It may or may not currently be *dyeable* in the NC Mall,
|
|
||||||
# because Dyeworks eligibility is often a limited-time event.
|
|
||||||
def dyeworks_base_buyable?
|
|
||||||
dyeworks_base_item.present? && dyeworks_base_item.currently_in_mall?
|
|
||||||
end
|
|
||||||
|
|
||||||
# Whether this is one of the few Dyeworks items that can be dyed in the NC
|
|
||||||
# Mall at any time, rather than as part of a limited-time event. (Owls tracks
|
|
||||||
# this, not us!)
|
|
||||||
def dyeworks_permanent?
|
|
||||||
return false if nc_trade_value.nil?
|
|
||||||
nc_trade_value.value_text.include?("Permanent Dyeworks")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Whether this is a Dyeworks item whose base item can currently be purchased
|
|
||||||
# in the NC Mall, then dyed via Dyeworks. (Owls tracks this last part!)
|
|
||||||
def dyeworks_buyable?
|
|
||||||
# TODO: Add support for limited-time Dyeworks items. Does Owls offer this
|
|
||||||
# info too? (At time of writing, there are no active Dyeworks events.)
|
|
||||||
dyeworks_base_buyable? && dyeworks_permanent?
|
|
||||||
end
|
|
||||||
|
|
||||||
DYEWORKS_NAME_PATTERN = %r{
|
|
||||||
^(
|
|
||||||
# Most Dyeworks items have a colon in the name.
|
|
||||||
Dyeworks\s+(?<color>.+?:)\s*(?<base>.+)
|
|
||||||
|
|
|
||||||
# But sometimes they omit it. If so, assume the first word is the color!
|
|
||||||
Dyeworks\s+(?<color>\S+)\s*(?<base>.+)
|
|
||||||
)$
|
|
||||||
}x
|
|
||||||
def inferred_dyeworks_base_item
|
|
||||||
name_match = name.match(DYEWORKS_NAME_PATTERN)
|
|
||||||
return nil if name_match.nil?
|
|
||||||
|
|
||||||
Item.find_by_name(name_match["base"])
|
|
||||||
end
|
|
||||||
|
|
||||||
def source
|
def source
|
||||||
if dyeworks_buyable?
|
if dyeworks_buyable?
|
||||||
:dyeworks
|
:dyeworks
|
||||||
|
|
106
app/models/item/dyeworks.rb
Normal file
106
app/models/item/dyeworks.rb
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
class Item
|
||||||
|
module Dyeworks
|
||||||
|
def dyeworks?
|
||||||
|
dyeworks_base_item.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Whether this is a Dyeworks item whose base item can currently be purchased
|
||||||
|
# in the NC Mall, then dyed via Dyeworks. (Owls tracks this last part!)
|
||||||
|
def dyeworks_buyable?
|
||||||
|
dyeworks_base_buyable? && dyeworks_dyeable?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Whether this is a Dyeworks item whose base item can currently be purchased
|
||||||
|
# in the NC Mall. It may or may not currently be *dyeable* in the NC Mall,
|
||||||
|
# because Dyeworks eligibility is often a limited-time event.
|
||||||
|
def dyeworks_base_buyable?
|
||||||
|
dyeworks_base_item.present? && dyeworks_base_item.currently_in_mall?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Whether this is a Dyeworks item that can be dyed in the NC Mall ~right now,
|
||||||
|
# either at any time or as a limited-time event. (Owls tracks this, not us!)
|
||||||
|
def dyeworks_dyeable?
|
||||||
|
dyeworks_permanent? || dyeworks_limited_active?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Whether this is one of the few Dyeworks items that can be dyed in the NC
|
||||||
|
# Mall at any time, rather than as part of a limited-time event. (Owls tracks
|
||||||
|
# this, not us!)
|
||||||
|
DYEWORKS_PERMANENT_PATTERN = /Permanent\s*Dyeworks/i
|
||||||
|
def dyeworks_permanent?
|
||||||
|
return false if nc_trade_value.nil?
|
||||||
|
nc_trade_value.value_text.match?(DYEWORKS_PERMANENT_PATTERN)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Whether this is a Dyeworks item that can be dyed in the NC Mall ~right
|
||||||
|
# now, as part of a limited-time event. (Owls tracks this, not us!)
|
||||||
|
#
|
||||||
|
# If we aren't sure of the final date, this will still return `true`, on
|
||||||
|
# the assumption it *is* dyeable right now and we just don't understand the
|
||||||
|
# details of what Owls told us.
|
||||||
|
def dyeworks_limited_active?
|
||||||
|
return false unless dyeworks_limited?
|
||||||
|
return true if dyeworks_limited_final_date.nil?
|
||||||
|
|
||||||
|
# NOTE: The application is configured to NST, so this should be
|
||||||
|
# equivalent to `Date.today`, but this is clearer and more correct imo!
|
||||||
|
today_in_nst = Time.find_zone("Pacific Time (US & Canada)").today
|
||||||
|
|
||||||
|
today_in_nst <= dyeworks_limited_final_date
|
||||||
|
end
|
||||||
|
|
||||||
|
# Whether this is a Dyeworks item that can only be dyed as part of a
|
||||||
|
# limited-time event. (This may return true even if the end date has
|
||||||
|
# passed, see `dyeworks_limited_active?`.) (Owls tracks this, not us!)
|
||||||
|
DYEWORKS_LIMITED_PATTERN = /Limited\s*Dyeworks/i
|
||||||
|
def dyeworks_limited?
|
||||||
|
return false if nc_trade_value.nil?
|
||||||
|
nc_trade_value.value_text.match?(DYEWORKS_LIMITED_PATTERN)
|
||||||
|
end
|
||||||
|
|
||||||
|
# If this is a limited-time Dyeworks item, this is the date we think the
|
||||||
|
# event will end on. Even if `dyeworks_limited?` returns true, this could
|
||||||
|
# still be `nil`, if we fail to parse this. (Owls tracks this, not us!)
|
||||||
|
DYEWORKS_LIMITED_FINAL_DATE_PATTERN =
|
||||||
|
/Dyeable\s*Thru\s*(?<month>[a-z]+)\s*(?<day>[0-9]+)/i
|
||||||
|
def dyeworks_limited_final_date
|
||||||
|
return nil unless dyeworks_limited?
|
||||||
|
|
||||||
|
match = nc_trade_value.value_text.
|
||||||
|
match(DYEWORKS_LIMITED_FINAL_DATE_PATTERN)
|
||||||
|
return nil if match.nil?
|
||||||
|
|
||||||
|
# Parse this "<Month> <Day>" date as the *next* such date: parse it as
|
||||||
|
# this year at first, then add a year if it turns out to be in the past.
|
||||||
|
#
|
||||||
|
# NOTE: This could return strange results if the Owls date contains
|
||||||
|
# something surprising! But the heuristic nature helps with e.g.
|
||||||
|
# flexibility if they abbreviate months, so let's lean into `Date.parse`.
|
||||||
|
match => {month:, day:}
|
||||||
|
date = Date.parse("#{month} #{day}, #{Date.today.year}")
|
||||||
|
date += 1.year if date < Date.today
|
||||||
|
|
||||||
|
date
|
||||||
|
end
|
||||||
|
|
||||||
|
# Infer what base item this Dyeworks item probably relates to, based on
|
||||||
|
# their names. We only use this when a new item is modeled to initialize
|
||||||
|
# the `dyeworks_base_item` relationship in the database; after that, we
|
||||||
|
# just use whatever the database says. (This allows manual overrides!)
|
||||||
|
DYEWORKS_NAME_PATTERN = %r{
|
||||||
|
^(
|
||||||
|
# Most Dyeworks items have a colon in the name.
|
||||||
|
Dyeworks\s+(?<color>.+?:)\s*(?<base>.+)
|
||||||
|
|
|
||||||
|
# But sometimes they omit it. If so, assume the first word is the color!
|
||||||
|
Dyeworks\s+(?<color>\S+)\s*(?<base>.+)
|
||||||
|
)$
|
||||||
|
}x
|
||||||
|
def inferred_dyeworks_base_item
|
||||||
|
name_match = name.match(DYEWORKS_NAME_PATTERN)
|
||||||
|
return nil if name_match.nil?
|
||||||
|
|
||||||
|
Item.find_by_name(name_match["base"])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -77,9 +77,24 @@
|
||||||
title: "This recipe is NOT currently scheduled to be removed " +
|
title: "This recipe is NOT currently scheduled to be removed " +
|
||||||
"from Dyeworks. It might not stay forever, but it's also " +
|
"from Dyeworks. It might not stay forever, but it's also " +
|
||||||
"not part of a known limited-time event, like most " +
|
"not part of a known limited-time event, like most " +
|
||||||
"Dyeworks items are."
|
"Dyeworks items are. (Thanks Owls team!)"
|
||||||
}
|
}
|
||||||
(Permanent)
|
(Permanent)
|
||||||
|
- elsif item.dyeworks_limited_final_date.present?
|
||||||
|
%span.dyeworks-timeframe{
|
||||||
|
title: "This recipe is part of a limited-time Dyeworks " +
|
||||||
|
"event. The last day you can dye this is " +
|
||||||
|
"#{item.dyeworks_limited_final_date.to_fs(:month_and_day)}. " +
|
||||||
|
"(Thanks Owls team!)"
|
||||||
|
}
|
||||||
|
(Thru #{item.dyeworks_limited_final_date.to_fs(:month_and_day)})
|
||||||
|
- elsif item.dyeworks_limited?
|
||||||
|
%span.dyeworks-timeframe{
|
||||||
|
title: "This recipe is part of a limited-time Dyeworks " +
|
||||||
|
"event, and is scheduled to be removed from the NC Mall " +
|
||||||
|
"soon. (Thanks Owls team!)"
|
||||||
|
}
|
||||||
|
(Limited-time)
|
||||||
|
|
||||||
%button{onclick: "alert('Todo!')"}
|
%button{onclick: "alert('Todo!')"}
|
||||||
= cart_icon alt: ""
|
= cart_icon alt: ""
|
||||||
|
|
|
@ -44,7 +44,7 @@ module OpenneoImpressItems
|
||||||
# These settings can be overridden in specific environments using the files
|
# These settings can be overridden in specific environments using the files
|
||||||
# in config/environments, which are processed later.
|
# in config/environments, which are processed later.
|
||||||
#
|
#
|
||||||
# config.time_zone = "Central Time (US & Canada)"
|
config.time_zone = "Pacific Time (US & Canada)"
|
||||||
# config.eager_load_paths << Rails.root.join("extras")
|
# config.eager_load_paths << Rails.root.join("extras")
|
||||||
|
|
||||||
config.i18n.fallbacks = true
|
config.i18n.fallbacks = true
|
||||||
|
|
1
config/initializers/date_formats.rb
Normal file
1
config/initializers/date_formats.rb
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Date::DATE_FORMATS[:month_and_day] = "%B %e"
|
|
@ -63,7 +63,7 @@ namespace :public_data do
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Pull and import the latest public data from production (dev only)"
|
desc "Pull and import the latest public data from production (dev only)"
|
||||||
task :pull => :environment do
|
task :pull => ["db:abort_if_pending_migrations", :environment] do
|
||||||
unless Rails.env.development?
|
unless Rails.env.development?
|
||||||
raise "Can only pull public data in development mode! This helps us " +
|
raise "Can only pull public data in development mode! This helps us " +
|
||||||
"ensure we won't overwrite the production database accidentally."
|
"ensure we won't overwrite the production database accidentally."
|
||||||
|
|
Loading…
Reference in a new issue