muck-raker 0.2.6 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/app/models/service.rb +7 -1
- data/muck-raker.gemspec +4 -5
- metadata +11 -5
- data/app/models/amazon.rb +0 -59
- data/app/models/amazon_request.rb +0 -110
- data/public/ecs_to_rss-wishlist.xslt +0 -41
- data/test/rails_root/test/unit/amazon_request_test.rb +0 -15
data/Rakefile
CHANGED
@@ -64,6 +64,7 @@ begin
|
|
64
64
|
gemspec.add_dependency "httparty"
|
65
65
|
gemspec.add_dependency "nokogiri"
|
66
66
|
gemspec.add_dependency "muck-feedbag"
|
67
|
+
gemspec.add_dependency "river"
|
67
68
|
gemspec.add_dependency "feedzirra"
|
68
69
|
gemspec.add_dependency "muck-engine"
|
69
70
|
gemspec.add_dependency "muck-users"
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.7
|
data/app/models/service.rb
CHANGED
@@ -99,6 +99,12 @@ class Service < ActiveRecord::Base
|
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
102
|
+
# Requires settings in global_config.yml
|
103
|
+
# For example:
|
104
|
+
# amazon_access_key_id: 'some key from your account'
|
105
|
+
# amazon_secret_access_key: 'the secret from your account'
|
106
|
+
# amazon_associate_tag: 'optional'
|
107
|
+
# ecs_to_rss_wishlist: "http://www.example.com/ecs_to_rss-wishlist.xslt"
|
102
108
|
def generate_uris(username = '', password = '', uri = '')
|
103
109
|
if self.name == 'Facebook'
|
104
110
|
# Facebook can't just use feeds like everyone else.
|
@@ -116,7 +122,7 @@ class Service < ActiveRecord::Base
|
|
116
122
|
elsif self.name == 'Amazon'
|
117
123
|
return [] if username.blank?
|
118
124
|
# Have to build and sign Amazon wishlist rss feeds
|
119
|
-
am = AmazonRequest.new(GlobalConfig.amazon_access_key_id, GlobalConfig.amazon_secret_access_key, GlobalConfig.amazon_associate_tag)
|
125
|
+
am = AmazonRequest.new(GlobalConfig.amazon_access_key_id, GlobalConfig.amazon_secret_access_key, GlobalConfig.ecs_to_rss_wishlist, GlobalConfig.amazon_associate_tag)
|
120
126
|
results = am.get_amazon_feeds(username) # username needs to be the user's Amazon email
|
121
127
|
results.collect { |result| OpenStruct.new(:url => result, :title => 'Amazon Wishlist') }
|
122
128
|
elsif !self.uri_data_template.blank? && !username.blank?
|
data/muck-raker.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{muck-raker}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.7"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Joel Duffin Justin Ball"]
|
@@ -40,8 +40,6 @@ Gem::Specification.new do |s|
|
|
40
40
|
"app/helpers/muck_raker_services_helper.rb",
|
41
41
|
"app/models/aggregation.rb",
|
42
42
|
"app/models/aggregation_feed.rb",
|
43
|
-
"app/models/amazon.rb",
|
44
|
-
"app/models/amazon_request.rb",
|
45
43
|
"app/models/attention.rb",
|
46
44
|
"app/models/click.rb",
|
47
45
|
"app/models/entry.rb",
|
@@ -474,7 +472,6 @@ Gem::Specification.new do |s|
|
|
474
472
|
"locales/zh-TW.yml",
|
475
473
|
"locales/zh.yml",
|
476
474
|
"muck-raker.gemspec",
|
477
|
-
"public/ecs_to_rss-wishlist.xslt",
|
478
475
|
"public/images/service_icons/16/amazon.png",
|
479
476
|
"public/images/service_icons/16/ask.png",
|
480
477
|
"public/images/service_icons/16/bibsonomy.png",
|
@@ -887,7 +884,6 @@ Gem::Specification.new do |s|
|
|
887
884
|
"test/rails_root/test/test_helper.rb",
|
888
885
|
"test/rails_root/test/unit/aggregation_feed_test.rb",
|
889
886
|
"test/rails_root/test/unit/aggregation_test.rb",
|
890
|
-
"test/rails_root/test/unit/amazon_request_test.rb",
|
891
887
|
"test/rails_root/test/unit/comment_test.rb",
|
892
888
|
"test/rails_root/test/unit/entry_test.rb",
|
893
889
|
"test/rails_root/test/unit/feed_parent_test.rb",
|
@@ -919,6 +915,7 @@ Gem::Specification.new do |s|
|
|
919
915
|
s.add_runtime_dependency(%q<httparty>, [">= 0"])
|
920
916
|
s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
|
921
917
|
s.add_runtime_dependency(%q<muck-feedbag>, [">= 0"])
|
918
|
+
s.add_runtime_dependency(%q<river>, [">= 0"])
|
922
919
|
s.add_runtime_dependency(%q<feedzirra>, [">= 0"])
|
923
920
|
s.add_runtime_dependency(%q<muck-engine>, [">= 0"])
|
924
921
|
s.add_runtime_dependency(%q<muck-users>, [">= 0"])
|
@@ -930,6 +927,7 @@ Gem::Specification.new do |s|
|
|
930
927
|
s.add_dependency(%q<httparty>, [">= 0"])
|
931
928
|
s.add_dependency(%q<nokogiri>, [">= 0"])
|
932
929
|
s.add_dependency(%q<muck-feedbag>, [">= 0"])
|
930
|
+
s.add_dependency(%q<river>, [">= 0"])
|
933
931
|
s.add_dependency(%q<feedzirra>, [">= 0"])
|
934
932
|
s.add_dependency(%q<muck-engine>, [">= 0"])
|
935
933
|
s.add_dependency(%q<muck-users>, [">= 0"])
|
@@ -942,6 +940,7 @@ Gem::Specification.new do |s|
|
|
942
940
|
s.add_dependency(%q<httparty>, [">= 0"])
|
943
941
|
s.add_dependency(%q<nokogiri>, [">= 0"])
|
944
942
|
s.add_dependency(%q<muck-feedbag>, [">= 0"])
|
943
|
+
s.add_dependency(%q<river>, [">= 0"])
|
945
944
|
s.add_dependency(%q<feedzirra>, [">= 0"])
|
946
945
|
s.add_dependency(%q<muck-engine>, [">= 0"])
|
947
946
|
s.add_dependency(%q<muck-users>, [">= 0"])
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: muck-raker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel Duffin Justin Ball
|
@@ -62,6 +62,16 @@ dependencies:
|
|
62
62
|
- !ruby/object:Gem::Version
|
63
63
|
version: "0"
|
64
64
|
version:
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: river
|
67
|
+
type: :runtime
|
68
|
+
version_requirement:
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
74
|
+
version:
|
65
75
|
- !ruby/object:Gem::Dependency
|
66
76
|
name: feedzirra
|
67
77
|
type: :runtime
|
@@ -145,8 +155,6 @@ files:
|
|
145
155
|
- app/helpers/muck_raker_services_helper.rb
|
146
156
|
- app/models/aggregation.rb
|
147
157
|
- app/models/aggregation_feed.rb
|
148
|
-
- app/models/amazon.rb
|
149
|
-
- app/models/amazon_request.rb
|
150
158
|
- app/models/attention.rb
|
151
159
|
- app/models/click.rb
|
152
160
|
- app/models/entry.rb
|
@@ -579,7 +587,6 @@ files:
|
|
579
587
|
- locales/zh-TW.yml
|
580
588
|
- locales/zh.yml
|
581
589
|
- muck-raker.gemspec
|
582
|
-
- public/ecs_to_rss-wishlist.xslt
|
583
590
|
- public/images/service_icons/16/amazon.png
|
584
591
|
- public/images/service_icons/16/ask.png
|
585
592
|
- public/images/service_icons/16/bibsonomy.png
|
@@ -1013,7 +1020,6 @@ test_files:
|
|
1013
1020
|
- test/rails_root/test/test_helper.rb
|
1014
1021
|
- test/rails_root/test/unit/aggregation_feed_test.rb
|
1015
1022
|
- test/rails_root/test/unit/aggregation_test.rb
|
1016
|
-
- test/rails_root/test/unit/amazon_request_test.rb
|
1017
1023
|
- test/rails_root/test/unit/comment_test.rb
|
1018
1024
|
- test/rails_root/test/unit/entry_test.rb
|
1019
1025
|
- test/rails_root/test/unit/feed_parent_test.rb
|
data/app/models/amazon.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
require 'openssl'
|
2
|
-
|
3
|
-
class Amazon
|
4
|
-
|
5
|
-
# Do we have support for the SHA-256 Secure Hash Algorithm?
|
6
|
-
# Note that Module#constants returns Strings in Ruby 1.8 and Symbols in 1.9.
|
7
|
-
DIGEST_SUPPORT = OpenSSL::Digest.constants.include?('SHA256') || OpenSSL::Digest.constants.include?(:SHA256)
|
8
|
-
|
9
|
-
# Requests are authenticated using the SHA-256 Secure Hash Algorithm.
|
10
|
-
DIGEST = OpenSSL::Digest::Digest.new('sha256') if DIGEST_SUPPORT
|
11
|
-
|
12
|
-
AMAZON_SITES = {
|
13
|
-
:ca => 'http://ecs.amazonaws.ca/onca/xml',
|
14
|
-
:de => 'http://ecs.amazonaws.de/onca/xml',
|
15
|
-
:fr => 'http://ecs.amazonaws.fr/onca/xml',
|
16
|
-
:jp => 'http://ecs.amazonaws.jp/onca/xml',
|
17
|
-
:uk => 'http://ecs.amazonaws.co.uk/onca/xml',
|
18
|
-
:us => 'http://ecs.amazonaws.com/onca/xml'
|
19
|
-
}
|
20
|
-
|
21
|
-
AMAZON_XSLT_SITES = {
|
22
|
-
:ca => 'http://xml-ca.amznxslt.com/onca/xml',
|
23
|
-
:de => 'http://xml-de.amznxslt.com/onca/xml',
|
24
|
-
:fr => 'http://xml-fr.amznxslt.com/onca/xml',
|
25
|
-
:jp => 'http://xml-jp.amznxslt.com/onca/xml',
|
26
|
-
:uk => 'http://xml-uk.amznxslt.com/onca/xml',
|
27
|
-
:us => 'http://xml-us.amznxslt.com/onca/xml'
|
28
|
-
}
|
29
|
-
|
30
|
-
class AmazonResultError < StandardError; end
|
31
|
-
|
32
|
-
# Sign an amazon query
|
33
|
-
# Requires openssl and that GlobalConfig.amazon_secret_access_key be defined.
|
34
|
-
# Based on ruby-aaws and documentation here
|
35
|
-
# http://www.caliban.org/ruby/ruby-aws/
|
36
|
-
# http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?RequestAuthenticationArticle.html
|
37
|
-
# Parameters
|
38
|
-
# query: The query to be signed
|
39
|
-
def self.sign_query(uri, query, amazon_secret_access_key)
|
40
|
-
raise 'SHA-256 not available in this version of openssl. Cannot sign Amazon requests.' unless DIGEST_SUPPORT
|
41
|
-
query << "&Timestamp=#{Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')}"
|
42
|
-
new_query = query.split('&').collect{|param| "#{param.split('=')[0]}=#{url_encode(param.split('=')[1])}"}.sort.join('&')
|
43
|
-
to_sign = "GET\n%s\n%s\n%s" % [uri.host, uri.path, new_query]
|
44
|
-
hmac = OpenSSL::HMAC.digest(DIGEST, amazon_secret_access_key, to_sign)
|
45
|
-
base64_hmac = [hmac].pack('m').chomp
|
46
|
-
signature = url_encode(base64_hmac)
|
47
|
-
new_query << "&Signature=#{signature}"
|
48
|
-
end
|
49
|
-
|
50
|
-
# Encode a string, such that it is suitable for HTTP transmission.
|
51
|
-
def self.url_encode(string)
|
52
|
-
return '' if string.nil?
|
53
|
-
# Shamelessly plagiarised from Wakou Aoyama's cgi.rb, but then altered slightly to please AWS.
|
54
|
-
string.gsub( /([^a-zA-Z0-9_.~-]+)/ ) do
|
55
|
-
'%' + $1.unpack( 'H2' * $1.bytesize ).join( '%' ).upcase
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
@@ -1,110 +0,0 @@
|
|
1
|
-
class AmazonRequest
|
2
|
-
include HTTParty
|
3
|
-
format :xml
|
4
|
-
|
5
|
-
# Initialize Amazon Request. Obtain valid Amazon credentials from your developer account
|
6
|
-
# Parameters:
|
7
|
-
# amazon_access_key_id: Valid Amazon access key
|
8
|
-
# amazon_secret_access_key: Valid Amazon secret access key
|
9
|
-
# amazon_associate_tag: Valid Amazon associates tag (optional)
|
10
|
-
# locale: Locale for the specific amazon site to use valid values are :ca, :de, :fr, :jp, :uk, :us (optional, default is us)
|
11
|
-
def initialize(amazon_access_key_id, amazon_secret_access_key, amazon_associate_tag = nil, locale = :us)
|
12
|
-
@amazon_access_key_id = amazon_access_key_id
|
13
|
-
@amazon_secret_access_key = amazon_secret_access_key
|
14
|
-
@amazon_associate_tag = amazon_associate_tag
|
15
|
-
@locale = locale
|
16
|
-
end
|
17
|
-
|
18
|
-
# Generate rss feeds for the give email
|
19
|
-
# Parameters:
|
20
|
-
# email: email for which to find feeds.
|
21
|
-
def get_amazon_feeds(email)
|
22
|
-
wishlists = get_customer_wishlists(email)
|
23
|
-
if !wishlists.blank?
|
24
|
-
wishlists = [wishlists] unless wishlists.is_a?(Array)
|
25
|
-
wishlist_ids = wishlists.collect{|list| list['ListId']}
|
26
|
-
generate_wishlist_rss(wishlist_ids)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
# Get matching id for the given email
|
31
|
-
# Parameters:
|
32
|
-
# email: customer's email.
|
33
|
-
def get_customer_id(email)
|
34
|
-
query = "Operation=CustomerContentSearch&Email=#{email}"
|
35
|
-
result = make_request(query)
|
36
|
-
if result['CustomerContentSearchResponse']['Customers']['TotalResults'].to_i > 0
|
37
|
-
result['CustomerContentSearchResponse']['Customers']['Customer'][0]
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# Get information for the given customer id
|
42
|
-
def get_customer_information(customer_id)
|
43
|
-
query = "Operation=CustomerContentLookup&ResponseGroup=CustomerLists&CustomerId=#{customer_id}"
|
44
|
-
make_request(query)
|
45
|
-
end
|
46
|
-
|
47
|
-
# Get customer's wishlist ids
|
48
|
-
def get_customer_wishlists(email)
|
49
|
-
query = "Operation=ListSearch&ListType=WishList&Email=#{email}"
|
50
|
-
result = make_request(query)
|
51
|
-
check_errors(result)
|
52
|
-
result['ListSearchResponse']['Lists']['List']
|
53
|
-
end
|
54
|
-
|
55
|
-
# For this method to work
|
56
|
-
# ecs_to_rss_wishlist must be set in global_config.yml
|
57
|
-
# For example:
|
58
|
-
# ecs_to_rss_wishlist: "http://www.example.com/ecs_to_rss-wishlist.xslt"
|
59
|
-
def generate_wishlist_rss(wishlist_ids)
|
60
|
-
feeds = []
|
61
|
-
wishlist_ids.each do |wishlist_id|
|
62
|
-
query = "Operation=ListLookup&ListType=WishList&ListId=#{wishlist_id}&ResponseGroup=ItemAttributes,ListItems,ListInfo,Offers&Sort=DateAdded&Style=#{GlobalConfig.ecs_to_rss_wishlist}"
|
63
|
-
feeds << make_xslt_request(query)
|
64
|
-
end
|
65
|
-
feeds
|
66
|
-
end
|
67
|
-
|
68
|
-
protected
|
69
|
-
|
70
|
-
def check_errors(result)
|
71
|
-
result.each_pair do |key, value|
|
72
|
-
if key == 'Errors'
|
73
|
-
if value['Error'].is_a?(Array)
|
74
|
-
raise Amazon::AmazonResultError, value['Error'].collect{|error| error['Message']}.join(' ')
|
75
|
-
else
|
76
|
-
raise Amazon::AmazonResultError, value['Error']['Message']
|
77
|
-
end
|
78
|
-
elsif value.is_a?(Hash)
|
79
|
-
check_errors(value)
|
80
|
-
elsif value.is_a?(Array)
|
81
|
-
value.each do |item|
|
82
|
-
if item.is_a?(Hash)
|
83
|
-
check_errors(item)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def make_request(query)
|
91
|
-
add_required_params(query)
|
92
|
-
uri = Amazon::AMAZON_SITES[@locale]
|
93
|
-
signed_query = Amazon.sign_query(URI.parse(uri), query, @amazon_secret_access_key)
|
94
|
-
AmazonRequest.get(uri, :query => signed_query)
|
95
|
-
end
|
96
|
-
|
97
|
-
def make_xslt_request(query)
|
98
|
-
add_required_params(query)
|
99
|
-
uri = Amazon::AMAZON_XSLT_SITES[@locale]
|
100
|
-
signed_query = Amazon.sign_query(URI.parse(uri), query, @amazon_secret_access_key)
|
101
|
-
"#{uri}?#{signed_query}"
|
102
|
-
end
|
103
|
-
|
104
|
-
def add_required_params(query)
|
105
|
-
query << "&Service=AWSECommerceService"
|
106
|
-
query << "&AWSAccessKeyId=#{@amazon_access_key_id}"
|
107
|
-
query << "&AssociateTag=#{@amazon_associate_tag}" if @amazon_associate_tag
|
108
|
-
query << "&Version=2009-07-01"
|
109
|
-
end
|
110
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8" ?>
|
2
|
-
<xsl:stylesheet version="1.0"
|
3
|
-
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
4
|
-
xmlns:aws="http://webservices.amazon.com/AWSECommerceService/2009-07-01">
|
5
|
-
|
6
|
-
<xsl:output method="xml"/>
|
7
|
-
|
8
|
-
<xsl:template match="/">
|
9
|
-
<rss version="2.0">
|
10
|
-
<channel>
|
11
|
-
<xsl:apply-templates select="aws:ListLookupResponse/aws:Lists/aws:List" />
|
12
|
-
</channel>
|
13
|
-
</rss>
|
14
|
-
</xsl:template>
|
15
|
-
|
16
|
-
<xsl:template match="aws:List">
|
17
|
-
<title>WishList for <xsl:value-of select="aws:CustomerName" /></title>
|
18
|
-
<link><xsl:value-of select="aws:ListURL"/></link>
|
19
|
-
<xsl:apply-templates select="aws:ListItem"/>
|
20
|
-
</xsl:template>
|
21
|
-
|
22
|
-
<xsl:template match="aws:ListItem">
|
23
|
-
<item>
|
24
|
-
<title><xsl:value-of select="aws:Item/aws:ItemAttributes/aws:Title" /></title>
|
25
|
-
<link><xsl:value-of select="aws:Item/aws:DetailPageURL" /></link>
|
26
|
-
<description>
|
27
|
-
<p>Author: <xsl:value-of select="aws:Item/aws:ItemAttributes/aws:Author" /></p>
|
28
|
-
<p>ISBN: <xsl:value-of select="aws:Item/aws:ItemAttributes/aws:ISBN" /></p>
|
29
|
-
<p>List Price: <xsl:value-of select="aws:Item/aws:ItemAttributes/aws:ListPrice/aws:FormattedPrice" /></p>
|
30
|
-
<p>Price: <xsl:value-of select="aws:Item/aws:OfferSummary/aws:LowestNewPrice/aws:FormattedPrice"/></p>
|
31
|
-
<xsl:apply-templates select="aws:Item/aws:ItemLinks/aws:ItemLink"/>
|
32
|
-
</description>
|
33
|
-
<guid><xsl:value-of select="aws:Item/aws:DetailPageURL" /></guid>
|
34
|
-
</item>
|
35
|
-
</xsl:template>
|
36
|
-
|
37
|
-
<xsl:template match="aws:ItemLink">
|
38
|
-
<a href="{aws:URL}"><xsl:value-of select="aws:Description" /></a>
|
39
|
-
</xsl:template>
|
40
|
-
|
41
|
-
</xsl:stylesheet>
|
@@ -1,15 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
-
|
3
|
-
class AmazonRequestTest < ActiveSupport::TestCase
|
4
|
-
|
5
|
-
context "amazon wish list" do
|
6
|
-
setup do
|
7
|
-
@email = 'justinball@gmail.com'
|
8
|
-
end
|
9
|
-
should "get wishlist" do
|
10
|
-
# result = AmazonRequest.get_amazon_feeds(@email)
|
11
|
-
# assert result.length > 0
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|