Add bare-bones rails nc_mall:sync
task, incl. NCMallRecord model
Currently we only load the homepage, so there's only actually one wearable item to sync up! But here's the task to do it! To do this, we also created the backing model NCMallRecord, where we'll save the current NC Mall state!
This commit is contained in:
parent
1f157b49da
commit
b6e18e10a5
5 changed files with 91 additions and 3 deletions
3
app/models/nc_mall_record.rb
Normal file
3
app/models/nc_mall_record.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
class NCMallRecord < ApplicationRecord
|
||||
belongs_to :item
|
||||
end
|
|
@ -72,8 +72,8 @@ module NCMall
|
|||
|
||||
{
|
||||
price: discount_price,
|
||||
start: item_info["discountBegin"],
|
||||
end: item_info["discountEnd"],
|
||||
begins_at: item_info["discountBegin"],
|
||||
ends_at: item_info["discountEnd"],
|
||||
}
|
||||
end
|
||||
|
||||
|
|
13
db/migrate/20240507235742_create_nc_mall_records.rb
Normal file
13
db/migrate/20240507235742_create_nc_mall_records.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
class CreateNCMallRecords < ActiveRecord::Migration[7.1]
|
||||
def change
|
||||
create_table :nc_mall_records do |t|
|
||||
t.references :item, type: :integer, null: false, foreign_key: true
|
||||
t.integer :price, null: false
|
||||
t.integer :discount_price
|
||||
t.datetime :discount_begins_at
|
||||
t.datetime :discount_ends_at
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
14
db/schema.rb
14
db/schema.rb
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.1].define(version: 2024_05_02_195157) do
|
||||
ActiveRecord::Schema[7.1].define(version: 2024_05_07_235742) do
|
||||
create_table "alt_styles", charset: "utf8mb4", collation: "utf8mb4_unicode_520_ci", force: :cascade do |t|
|
||||
t.integer "species_id", null: false
|
||||
t.integer "color_id", null: false
|
||||
|
@ -154,6 +154,17 @@ ActiveRecord::Schema[7.1].define(version: 2024_05_02_195157) do
|
|||
t.string "pet_name", limit: 128, null: false
|
||||
end
|
||||
|
||||
create_table "nc_mall_records", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t|
|
||||
t.integer "item_id", null: false
|
||||
t.integer "price", null: false
|
||||
t.integer "discount_price"
|
||||
t.datetime "discount_begins_at"
|
||||
t.datetime "discount_ends_at"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["item_id"], name: "index_nc_mall_records_on_item_id"
|
||||
end
|
||||
|
||||
create_table "neopets_connections", id: :integer, charset: "utf8mb4", collation: "utf8mb4_unicode_520_ci", force: :cascade do |t|
|
||||
t.integer "user_id"
|
||||
t.string "neopets_username"
|
||||
|
@ -278,5 +289,6 @@ ActiveRecord::Schema[7.1].define(version: 2024_05_02_195157) do
|
|||
|
||||
add_foreign_key "alt_styles", "colors"
|
||||
add_foreign_key "alt_styles", "species"
|
||||
add_foreign_key "nc_mall_records", "items"
|
||||
add_foreign_key "outfits", "alt_styles"
|
||||
end
|
||||
|
|
60
lib/tasks/nc_mall.rake
Normal file
60
lib/tasks/nc_mall.rake
Normal file
|
@ -0,0 +1,60 @@
|
|||
namespace :nc_mall do
|
||||
desc "Sync our NCMallRecord table with the live NC Mall"
|
||||
task :sync => :environment do
|
||||
# Log to STDOUT.
|
||||
Rails.logger = Logger.new(STDOUT)
|
||||
|
||||
# First, load all records of what's being sold in the live NC Mall.
|
||||
# TODO: Load from other pages, too!
|
||||
live_item_records = NCMall.load_home_page[:items]
|
||||
|
||||
# Then, get the existing NC Mall records in our database. (We include the
|
||||
# items, to be able to output the item name during logging.)
|
||||
existing_records = NCMallRecord.includes(:item).all
|
||||
existing_records_by_item_id = existing_records.to_h { |r| [r.item_id, r] }
|
||||
|
||||
# Additionally, check which of the item IDs in the live records are items
|
||||
# we've seen before. (We'll skip records for items we don't know.)
|
||||
live_item_ids = live_item_records.map { |r| r[:id] }
|
||||
recognized_item_ids = Item.where(id: live_item_ids).pluck(:id).to_set
|
||||
Rails.logger.debug "We recognize #{recognized_item_ids.size} of these items"
|
||||
|
||||
# For each record in the live NC Mall, check if there's an existing record.
|
||||
# If so, update it, and remove it from the existing records hash. If not,
|
||||
# create it.
|
||||
live_item_records.each do |record_data|
|
||||
# If we don't recognize this item ID in our database already, skip it.
|
||||
next unless recognized_item_ids.include?(record_data[:id])
|
||||
|
||||
record = existing_records_by_item_id.delete(record_data[:id]) ||
|
||||
NCMallRecord.new
|
||||
record.item_id = record_data[:id]
|
||||
record.price = record_data[:price]
|
||||
record.discount_price = record_data.dig(:discount, :price)
|
||||
record.discount_begins_at = record_data.dig(:discount, :begins_at)
|
||||
record.discount_ends_at = record_data.dig(:discount, :ends_at)
|
||||
if record.save
|
||||
Rails.logger.info "Saved record for item #{record_data[:name]}"
|
||||
else
|
||||
Rails.logger.error "Failed to save record for item " +
|
||||
"#{record_data[:name]}: " +
|
||||
"#{record.errors.full_messages.join("; ")}: " +
|
||||
"#{record.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
# For each existing record remaining in the existing records hash, this
|
||||
# means there was no live record corresponding to it during this sync.
|
||||
# Delete it!
|
||||
existing_records_by_item_id.values.each do |record|
|
||||
item_name = record.item&.name || "<item not found>"
|
||||
if record.destroy
|
||||
Rails.logger.info "Destroyed record #{record.id} for item " +
|
||||
"#{item_name}"
|
||||
else
|
||||
Rails.logger.error "Failed to destroy record #{record.id} for " +
|
||||
"item #{item_name}: #{record.inspect}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue