muck-raker 0.2.6 → 0.2.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|