diff --git a/app/controllers/closet_pages_controller.rb b/app/controllers/closet_pages_controller.rb
deleted file mode 100644
index c0912883..00000000
--- a/app/controllers/closet_pages_controller.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-class ClosetPagesController < ApplicationController
- include ActionView::Helpers::TextHelper
-
- before_filter :authenticate_user!, :build_closet_page
-
- rescue_from ClosetPage::ParseError, :with => :on_parse_error
-
- def create
- if params[:closet_page] && params[:closet_page][:source]
- @closet_page.index = params[:closet_page][:index]
- @closet_page.source = params[:closet_page][:source]
-
- saved_counts = @closet_page.save_hangers!
-
- any_created = saved_counts[:created] > 0
- any_updated = saved_counts[:updated] > 0
- if any_created || any_updated
- message = "Page #{@closet_page.index} saved! We "
- message << "added " + pluralize(saved_counts[:created], 'item') + " to your closet" if any_created
- message << " and " if any_created && any_updated
- message << "updated the count on " + pluralize(saved_counts[:updated], 'item') if any_updated
- message << ". "
- else
- message = "Success! We checked that page, and we already had all this data recorded. "
- end
-
- unless @closet_page.unknown_item_names.empty?
- message << "We also found " +
- pluralize(@closet_page.unknown_item_names.size, 'item') +
- " we didn't recognize: " +
- @closet_page.unknown_item_names.to_sentence +
- ". Please put each item on your pet and type its name in on the " +
- "home page so we can have a record of it. Thanks! "
- end
-
- if @closet_page.last?
- message << "That was the last page of your Neopets closet."
- destination = user_closet_hangers_path(current_user)
- else
- message << "Now the frame should contain page #{@closet_page.index + 1}. Paste that source code over, too."
- destination = {:action => :new, :index => (@closet_page.index + 1)}
- end
-
- flash[:success] = message
- redirect_to destination
- else
- redirect_to :action => :new
- end
- end
-
- def new
- @closet_page.index ||= 1
- end
-
- protected
-
- def build_closet_page
- @closet_page = ClosetPage.new(current_user)
- @closet_page.index = params[:index]
- end
-
- def on_parse_error
- flash[:alert] = "We had trouble reading your source code. Is it a valid HTML document? Make sure you pasted the computery-looking result of clicking View Frame Source, and not the pretty page itself."
- render :action => :new
- end
-end
-
diff --git a/app/controllers/neopets_pages_controller.rb b/app/controllers/neopets_pages_controller.rb
new file mode 100644
index 00000000..a930789d
--- /dev/null
+++ b/app/controllers/neopets_pages_controller.rb
@@ -0,0 +1,79 @@
+class NeopetsPagesController < ApplicationController
+ include ActionView::Helpers::TextHelper
+
+ before_filter :authenticate_user!, :build_neopets_page
+
+ rescue_from ClosetPage::ParseError, :with => :on_parse_error
+
+ def create
+ if @page_params && @page_params[:source]
+ @neopets_page.index = @page_params[:index]
+ @neopets_page.source = @page_params[:source]
+
+ saved_counts = @neopets_page.save_hangers!
+
+ any_created = saved_counts[:created] > 0
+ any_updated = saved_counts[:updated] > 0
+ if any_created || any_updated
+ message = "Page #{@neopets_page.index} saved! We "
+ message << "added " + pluralize(saved_counts[:created], 'item') + " to the items you own" if any_created
+ message << " and " if any_created && any_updated
+ message << "updated the count on " + pluralize(saved_counts[:updated], 'item') if any_updated
+ message << ". "
+ elsif @neopets_page.hangers.size > 1
+ message = "Success! We checked that page, and we already had all this data recorded. "
+ else
+ message = "Success! We checked that page, and there were no wearables to add. "
+ end
+
+ unless @neopets_page.unknown_item_names.empty?
+ message << "We also found " +
+ pluralize(@neopets_page.unknown_item_names.size, 'item') +
+ " we didn't recognize: " +
+ @neopets_page.unknown_item_names.to_sentence +
+ ". Please put each item on your pet and type its name in on the " +
+ "home page so we can have a record of it. Thanks! "
+ end
+
+ if @neopets_page.last?
+ message << "That was the last page of your Neopets #{@neopets_page.name}."
+ destination = user_closet_hangers_path(current_user)
+ else
+ message << "Now the frame should contain page #{@neopets_page.index + 1}. Paste that source code over, too."
+ destination = {:action => :new, :index => (@neopets_page.index + 1)}
+ end
+
+ flash[:success] = message
+ redirect_to destination
+ else
+ redirect_to :action => :new
+ end
+ end
+
+ def new
+ @neopets_page.index ||= 1
+ end
+
+ protected
+
+ TYPES = {
+ 'closet' => ClosetPage,
+ 'sdb' => SafetyDepositPage
+ }
+ def build_neopets_page
+ type_class = TYPES[params[:type]]
+
+ @neopets_page = type_class.new(current_user)
+ @neopets_page.index = params[:index]
+ @page_params = params[type_class.model_name.singular]
+ end
+
+ def on_parse_error(e)
+ Rails.logger.info "Neopets page parse error: #{e.message}"
+ flash[:alert] = "We had trouble reading your source code. Is it a valid " +
+ "HTML document? Make sure you pasted the computery-looking result of " +
+ "clicking View Frame Source, and not the pretty page itself. "
+ render :action => :new
+ end
+end
+
diff --git a/app/models/closet_page.rb b/app/models/closet_page.rb
index 9ac91838..f58a466f 100644
--- a/app/models/closet_page.rb
+++ b/app/models/closet_page.rb
@@ -4,7 +4,7 @@ class ClosetPage
include ActiveModel::Conversion
extend ActiveModel::Naming
- SELECTORS = {
+ @selectors = {
:items => "form[action=\"process_closet.phtml\"] tr[bgcolor!=silver][bgcolor!=\"#E4E4E4\"]",
:item_thumbnail => "img",
:item_name => "td:nth-child(2)",
@@ -26,6 +26,10 @@ class ClosetPage
@index == @total_pages
end
+ def name
+ 'closet'
+ end
+
def persisted?
false
end
@@ -58,47 +62,79 @@ class ClosetPage
protected
def element(selector_name, parent)
- parent.at_css(SELECTORS[selector_name]) ||
- raise(ParseError, "Closet #{selector_name} element not found in #{parent.inspect}")
+ parent.at_css(self.class.selectors[selector_name]) ||
+ raise(ParseError, "#{selector_name} element not found")
end
def elements(selector_name, parent)
- parent.css(SELECTORS[selector_name])
+ parent.css(self.class.selectors[selector_name])
+ end
+
+ def find_id(row)
+ element(:item_remove, row)['name']
+ end
+
+ def find_index(page_selector)
+ element(:selected, page_selector)['value'].to_i
+ end
+
+ def find_items(doc)
+ elements(:items, doc)
+ end
+
+ def find_name(row)
+ # For normal items, the td contains essentially:
+ # NAME
OPTIONAL ADJECTIVE
+ # For PB items, the td contains:
+ # NAME
OPTIONAL ADJECTIVE
+ # So, we want the first text node. If it's a PB item, that's the first
+ # child. If it's a normal item, it's the first child 's child.
+ name_el = element(:item_name, row).children[0]
+ name_el = name_el.children[0] if name_el.name == 'b'
+ name_el.text
+ end
+
+ def find_page_selector(doc)
+ element(:page_select, doc)
+ end
+
+ def find_quantity(row)
+ element(:item_quantity, row).text.to_i
+ end
+
+ def find_thumbnail_url(row)
+ element(:item_thumbnail, row)['src']
+ end
+
+ def find_total_pages(page_selector)
+ page_selector.children.size
end
def parse_source!(source)
doc = Nokogiri::HTML(source)
- page_selector = element(:page_select, doc)
- @total_pages = page_selector.children.size
- @index = element(:selected, page_selector)['value'].to_i
+ page_selector = find_page_selector(doc)
+ @total_pages = find_total_pages(page_selector)
+ @index = find_index(page_selector)
items_data = {
:id => {},
:thumbnail_url => {}
}
- # Go through the items, and find the ID/thumbnail for each and data with it
- elements(:items, doc).each do |row|
- # For normal items, the td contains essentially:
- # NAME
OPTIONAL ADJECTIVE
- # For PB items, the td contains:
- # NAME
OPTIONAL ADJECTIVE
- # So, we want the first text node. If it's a PB item, that's the first
- # child. If it's a normal item, it's the first child 's child.
- name_el = element(:item_name, row).children[0]
- name_el = name_el.children[0] if name_el.name == 'b'
+ # Go through the items, and find the ID/thumbnail for each and data with it
+ find_items(doc).each do |row|
data = {
- :name => name_el.text,
- :quantity => element(:item_quantity, row).text.to_i
+ :name => find_name(row),
+ :quantity => find_quantity(row)
}
- if id = element(:item_remove, row)['name']
+ if id = find_id(row)
id = id.to_i
items_data[:id][id] = data
else # if this is a pb item, which does not give ID, go by thumbnail
- thumbnail_url = element(:item_thumbnail, row)['src']
+ thumbnail_url = find_thumbnail_url(row)
items_data[:thumbnail_url][thumbnail_url] = data
end
end
@@ -133,6 +169,10 @@ class ClosetPage
end
end
+ def self.selectors
+ @selectors
+ end
+
class ParseError < RuntimeError;end
end
diff --git a/app/models/safety_deposit_page.rb b/app/models/safety_deposit_page.rb
new file mode 100644
index 00000000..09619fdf
--- /dev/null
+++ b/app/models/safety_deposit_page.rb
@@ -0,0 +1,39 @@
+class SafetyDepositPage < ClosetPage
+ @selectors = {
+ :items => "#content tr[bgcolor=\"#DFEAF7\"]",
+ :item_thumbnail => "img",
+ :item_name => "td:nth-child(2)",
+ :item_quantity => "td:nth-child(5)",
+ :item_remove => "input",
+ :page_select => "select[name=offset]",
+ :selected => "option[selected]"
+ }
+
+ def name
+ 'SDB'
+ end
+
+ def url
+ "http://www.neopets.com/safetydeposit.phtml?offset=#{offset}"
+ end
+
+ protected
+
+ REMOVE_NAME_REGEX = /\[([0-9]+)\]/
+ def find_id(*args)
+ name = super
+ unless match = name.match(REMOVE_NAME_REGEX)
+ raise ParseError, "Remove Item input name format was unexpected: #{name}.inspect"
+ end
+ match[1]
+ end
+
+ def find_index(*args)
+ (super / 30) + 1
+ end
+
+ def offset
+ @index ? (@index.to_i - 1) * 30 : 0
+ end
+end
+
diff --git a/app/stylesheets/closet_pages/_new.sass b/app/stylesheets/neopets_pages/_new.sass
similarity index 92%
rename from app/stylesheets/closet_pages/_new.sass
rename to app/stylesheets/neopets_pages/_new.sass
index ceb49654..9a95aa8c 100644
--- a/app/stylesheets/closet_pages/_new.sass
+++ b/app/stylesheets/neopets_pages/_new.sass
@@ -1,4 +1,4 @@
-body.closet_pages-new, body.closet_pages-create
+body.neopets_pages-new, body.neopets_pages-create
#title
float: left
diff --git a/app/stylesheets/screen.sass b/app/stylesheets/screen.sass
index c8db393f..289e15f3 100644
--- a/app/stylesheets/screen.sass
+++ b/app/stylesheets/screen.sass
@@ -9,7 +9,7 @@
@import closet_hangers/index
@import closet_hangers/petpage
@import closet_lists/form
-@import closet_pages/new
+@import neopets_pages/new
@import contributions/index
@import items
@import items/index
diff --git a/app/views/closet_hangers/index.html.haml b/app/views/closet_hangers/index.html.haml
index 91509480..c8aa24a4 100644
--- a/app/views/closet_hangers/index.html.haml
+++ b/app/views/closet_hangers/index.html.haml
@@ -74,8 +74,9 @@
%label{:for => 'closet-hangers-share-box'} Public URL:
%input#closet-hangers-share-box{:type => 'text', :value => user_closet_hangers_url(@user), :readonly => true}
- = link_to "Import from Neopets closet", new_closet_page_path
- = link_to "Export to Neopets petpage", petpage_user_closet_hangers_path(@user)
+ = link_to "Import from closet", new_closet_page_path
+ = link_to "Import from SDB", new_safety_deposit_page_path
+ = link_to "Export to petpage", petpage_user_closet_hangers_path(@user)
diff --git a/app/views/closet_pages/new.html.haml b/app/views/neopets_pages/new.html.haml
similarity index 67%
rename from app/views/closet_pages/new.html.haml
rename to app/views/neopets_pages/new.html.haml
index e2f6f5d6..2850f517 100644
--- a/app/views/closet_pages/new.html.haml
+++ b/app/views/neopets_pages/new.html.haml
@@ -1,26 +1,26 @@
-- title "Import from closet, Page #{@closet_page.index}"
+- title "Import from #{@neopets_page.name}, Page #{@neopets_page.index}"
- content_for :before_flashes do
= link_to 'Back to Your Items', user_closet_hangers_path(current_user), :id => 'back-to-items'
-= form_for @closet_page, :html => {:id => 'closet-page-form'} do |f|
+= form_for @neopets_page, :html => {:id => 'closet-page-form'} do |f|
= f.hidden_field :index
#closet-page-frame-wrapper
%span
- %strong Page #{@closet_page.index}
- of your closet
- %iframe#closet-page-frame{:src => @closet_page.url}
+ %strong Page #{@neopets_page.index}
+ of your #{@neopets_page.name}
+ %iframe#closet-page-frame{:src => @neopets_page.url}
#closet-page-source
= f.label :source, "Paste source code below"
= f.text_area :source
- = f.submit 'Add items to closet'
+ = f.submit 'Import items'
:markdown
- **Welcome to the bulk closet importer!** We're going to make it as
- easy as possible to import your Neopets.com closet data into your Dress to
- Impress closet. Here's how it works.
+ **Welcome to the bulk #{@neopets_page.name} importer!** We're going to make it as
+ easy as possible to import your Neopets.com #{@neopets_page.name} data into your Dress to
+ Impress items list. Here's how it works.
1. Check the framed Neopets.com window on the left, pointing to
- [page #{@closet_page.index} of your closet][cp].
+ [page #{@neopets_page.index} of your #{@neopets_page.name}][cp].
* **Confirm that you're logged in.** If you're logged into
Neopets, but the above frame says that you're not, try enabling
"third-party cookies" in your browser. (Most have that on by default.)
@@ -29,7 +29,7 @@
web programmer pro who can check that the frame does, in fact, point
to Neopets.com. To be safe,
#{link_to_neopets_login "pull up another window, check the URL, and log in safely"}.
- * **Confirm that the page is, in fact, your closet.** Similarly, don't
+ * **Confirm that the page is, in fact, your #{@neopets_page.name}.** Similarly, don't
just trust a website when they tell you to copy-paste the source code
of another site. Instead, check that the page is what it is supposed to
be and does not contain any information you didn't mean to give out.
@@ -39,7 +39,7 @@
* **In Firefox,** right-click the frame, choose **This Frame**, then **View Frame Source**.
* In other browsers, right-click, and look for something similar. If you're
still having trouble, try
- #{link_to "viewing the page in a new window", @closet_page.url, :target => "_blank"},
+ #{link_to "viewing the page in a new window", @neopets_page.url, :target => "_blank"},
right-clicking, and choosing View Source.
3. Highlight the entire source code, and copy-paste it into the box on the right.
@@ -48,10 +48,10 @@
4. Submit!
* We'll analyze the code you sent us, grab exclusively the identity and
- quantity of items in your closet, and add that to your Dress to Impress
- closet. I promise it's all safe, but, if you're concerned, find a
+ quantity of items in your #{@neopets_page.name}, and add that to your Dress to Impress
+ items list. I promise it's all safe, but, if you're concerned, find a
programmer buddy and [check out the source code to be sure][source].
- [cp]: #{@closet_page.url}
+ [cp]: #{@neopets_page.url}
[source]: http://github.com/matchu/openneo-impress-rails
diff --git a/config/routes.rb b/config/routes.rb
index 7a19db34..a0b6dc4e 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -30,7 +30,13 @@ OpenneoImpressItems::Application.routes.draw do |map|
resources :pet_attributes, :only => [:index]
resources :swf_assets, :only => [:index, :show]
- resources :closet_pages, :only => [:new, :create], :path => 'closet/pages'
+ scope 'import' do
+ resources :closet_pages, :only => [:new, :create],
+ :controller => 'neopets_pages', :path => 'closet/pages', :type => 'closet'
+
+ resources :safety_deposit_pages, :only => [:new, :create],
+ :controller => 'neopets_pages', :path => 'sdb/pages', :type => 'sdb'
+ end
match '/users/current-user/outfits' => 'outfits#index', :as => :current_user_outfits
diff --git a/public/stylesheets/compiled/screen.css b/public/stylesheets/compiled/screen.css
index 329855cc..45d43f7e 100644
--- a/public/stylesheets/compiled/screen.css
+++ b/public/stylesheets/compiled/screen.css
@@ -1348,16 +1348,16 @@ body.closet_lists-new form ul.fields .hint, body.closet_lists-create form ul.fie
font-size: 85%;
}
-/* line 3, ../../../app/stylesheets/closet_pages/_new.sass */
-body.closet_pages-new #title, body.closet_pages-create #title {
+/* line 3, ../../../app/stylesheets/neopets_pages/_new.sass */
+body.neopets_pages-new #title, body.neopets_pages-create #title {
float: left;
}
-/* line 6, ../../../app/stylesheets/closet_pages/_new.sass */
-body.closet_pages-new .flash, body.closet_pages-create .flash {
+/* line 6, ../../../app/stylesheets/neopets_pages/_new.sass */
+body.neopets_pages-new .flash, body.neopets_pages-create .flash {
clear: both;
}
-/* line 9, ../../../app/stylesheets/closet_pages/_new.sass */
-body.closet_pages-new #back-to-items, body.closet_pages-create #back-to-items {
+/* line 9, ../../../app/stylesheets/neopets_pages/_new.sass */
+body.neopets_pages-new #back-to-items, body.neopets_pages-create #back-to-items {
/* http://www.zurb.com/blog_uploads/0000/0617/buttons-03.html */
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
@@ -1378,69 +1378,69 @@ body.closet_pages-new #back-to-items, body.closet_pages-create #back-to-items {
margin-top: 0.75em;
}
/* line 34, ../../../app/stylesheets/partials/clean/_mixins.sass */
-body.closet_pages-new #back-to-items:hover, body.closet_pages-create #back-to-items:hover {
+body.neopets_pages-new #back-to-items:hover, body.neopets_pages-create #back-to-items:hover {
background-color: #005300;
}
/* line 53, ../../../app/stylesheets/partials/clean/_mixins.sass */
-body.closet_pages-new #back-to-items:hover, body.closet_pages-create #back-to-items:hover {
+body.neopets_pages-new #back-to-items:hover, body.neopets_pages-create #back-to-items:hover {
color: white;
}
/* line 55, ../../../app/stylesheets/partials/clean/_mixins.sass */
-body.closet_pages-new #back-to-items:active, body.closet_pages-create #back-to-items:active {
+body.neopets_pages-new #back-to-items:active, body.neopets_pages-create #back-to-items:active {
top: 1px;
}
-/* line 15, ../../../app/stylesheets/closet_pages/_new.sass */
-body.closet_pages-new #closet-page-form, body.closet_pages-create #closet-page-form {
+/* line 15, ../../../app/stylesheets/neopets_pages/_new.sass */
+body.neopets_pages-new #closet-page-form, body.neopets_pages-create #closet-page-form {
overflow: hidden;
display: inline-block;
clear: both;
margin-bottom: 1em;
}
/* line 8, ../../../app/stylesheets/partials/clean/_mixins.sass */
-body.closet_pages-new #closet-page-form, body.closet_pages-create #closet-page-form {
+body.neopets_pages-new #closet-page-form, body.neopets_pages-create #closet-page-form {
display: block;
}
-/* line 20, ../../../app/stylesheets/closet_pages/_new.sass */
-body.closet_pages-new #closet-page-frame-wrapper, body.closet_pages-create #closet-page-frame-wrapper {
+/* line 20, ../../../app/stylesheets/neopets_pages/_new.sass */
+body.neopets_pages-new #closet-page-frame-wrapper, body.neopets_pages-create #closet-page-frame-wrapper {
float: left;
margin-right: 2%;
width: 48%;
}
-/* line 25, ../../../app/stylesheets/closet_pages/_new.sass */
-body.closet_pages-new #closet-page-frame, body.closet_pages-create #closet-page-frame {
+/* line 25, ../../../app/stylesheets/neopets_pages/_new.sass */
+body.neopets_pages-new #closet-page-frame, body.neopets_pages-create #closet-page-frame {
height: 19em;
width: 100%;
}
-/* line 29, ../../../app/stylesheets/closet_pages/_new.sass */
-body.closet_pages-new #closet-page-source, body.closet_pages-create #closet-page-source {
+/* line 29, ../../../app/stylesheets/neopets_pages/_new.sass */
+body.neopets_pages-new #closet-page-source, body.neopets_pages-create #closet-page-source {
float: left;
width: 50%;
}
-/* line 33, ../../../app/stylesheets/closet_pages/_new.sass */
-body.closet_pages-new #closet-page-source label, body.closet_pages-create #closet-page-source label {
+/* line 33, ../../../app/stylesheets/neopets_pages/_new.sass */
+body.neopets_pages-new #closet-page-source label, body.neopets_pages-create #closet-page-source label {
font-weight: bold;
}
-/* line 36, ../../../app/stylesheets/closet_pages/_new.sass */
-body.closet_pages-new #closet-page-source textarea, body.closet_pages-create #closet-page-source textarea {
+/* line 36, ../../../app/stylesheets/neopets_pages/_new.sass */
+body.neopets_pages-new #closet-page-source textarea, body.neopets_pages-create #closet-page-source textarea {
height: 19em;
}
-/* line 40, ../../../app/stylesheets/closet_pages/_new.sass */
-body.closet_pages-new ol, body.closet_pages-create ol {
+/* line 40, ../../../app/stylesheets/neopets_pages/_new.sass */
+body.neopets_pages-new ol, body.neopets_pages-create ol {
padding-left: 1em;
}
-/* line 43, ../../../app/stylesheets/closet_pages/_new.sass */
-body.closet_pages-new ol > li, body.closet_pages-create ol > li {
+/* line 43, ../../../app/stylesheets/neopets_pages/_new.sass */
+body.neopets_pages-new ol > li, body.neopets_pages-create ol > li {
margin-bottom: 1em;
}
-/* line 46, ../../../app/stylesheets/closet_pages/_new.sass */
-body.closet_pages-new ol ul, body.closet_pages-create ol ul {
+/* line 46, ../../../app/stylesheets/neopets_pages/_new.sass */
+body.neopets_pages-new ol ul, body.neopets_pages-create ol ul {
font-size: 85%;
margin-bottom: 1em;
margin-top: 0;
padding-left: 1em;
}
-/* line 53, ../../../app/stylesheets/closet_pages/_new.sass */
-body.closet_pages-new ol p, body.closet_pages-create ol p {
+/* line 53, ../../../app/stylesheets/neopets_pages/_new.sass */
+body.neopets_pages-new ol p, body.neopets_pages-create ol p {
margin: 0;
}