sapoci-connect 0.1.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/CHANGELOG.md ADDED
@@ -0,0 +1,41 @@
1
+ *2011-10-15 (0.1.7)*
2
+
3
+ * Accept GET and POST on ./bin/sapoci-search
4
+
5
+ *2011-09-22 (0.1.6)*
6
+
7
+ * Fixed parsing issues with longtext field on HTML (from SAPOCI gem)
8
+
9
+ *2011-09-07 (0.1.5)*
10
+
11
+ * Raise RedirectWithoutLocation error when returning
12
+ HTTP status 302 without setting the HTTP Location header
13
+
14
+ *2011-09-06 (0.1.4)*
15
+
16
+ * Make POSTs really post as encoded name/value pairs in the body
17
+
18
+ *2011-09-06 (0.1.3)*
19
+
20
+ * Changed middleware for background search to put
21
+ `SAPOCI::Document` into `response.env[:sapoci]`
22
+ instead of `response.env[:body]`.
23
+
24
+ *2011-09-06 (0.1.2)*
25
+
26
+ * Changed semantics of search to always add HTTP method,
27
+ i.e. `:get` or `:post`
28
+ * Added test for timeout errors
29
+ * Added test for relative redirects (i.e. redirects without hostname)
30
+
31
+
32
+ *2011-08-30 (0.1.1)*
33
+
34
+ * Simplify API by separating connection initialization (Faraday) and OCI
35
+ handling via Faraday middleware.
36
+ * Added `bin/sapoci-search` script to perform, you name it, SAP OCI
37
+ background search.
38
+
39
+ *2011-08-29 (0.1.0)*
40
+
41
+ * Initial version, supporting OCI background search only.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2007-2011 Oliver Eilhard
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
data/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # SAP OCI Connect
2
+
3
+ We use this library to work with eprocurement punchout systems that
4
+ comply to the SAP OCI 4.0 specification.
5
+
6
+ ## Features
7
+
8
+ ### SAP OCI Background Search
9
+
10
+ It's as simple as this:
11
+
12
+ conn = Faraday.new("http://onlineshop.com/path", :params => {"token" => "123"}) do |builder|
13
+ builder.use SAPOCI::Connect::Middleware::FollowRedirects
14
+ builder.use SAPOCI::Connect::Middleware::PassCookies
15
+ builder.use SAPOCI::Connect::Middleware::BackgroundSearch
16
+ builder.adapter :net_http
17
+ end
18
+
19
+ conn.options[:timeout] = 5
20
+ conn.options[:open_timeout] = 10
21
+
22
+ resp = SAPOCI::Connect.search(:get, conn, "toner", "http://return.to/me")
23
+ puts resp.status # => 200
24
+ puts resp.body # => <SAPOCI::Document>
25
+ puts resp.env[:raw_body] # => "<html>...</html>"
26
+
27
+ Review [Faraday](https://github.com/technoweenie/faraday) for details on
28
+ connection initiation.
29
+
30
+ ## Testing
31
+
32
+ Here's how to test locally:
33
+
34
+ $ bundle update
35
+ $ # Start a second console
36
+ $ ruby test/live_server.rb
37
+ $ # Back in first console
38
+ $ rake
39
+
40
+ To test external servers, use the REMOTE environment variable:
41
+
42
+ $ REMOTE="http://remote-site.com/Login.aspx?u=demo&p=secret" rake
43
+
44
+ ## Credits
45
+
46
+ Standing on the shoulder of giants, where giants include:
47
+
48
+ * Rick Olson for [faraday](https://github.com/technoweenie/faraday),
49
+ * Ilya Grigorik for [em-synchrony](https://github.com/igrigorik/em-synchrony),
50
+ [em-http-request](https://github.com/igrigorik/em-http-request) and stuff,
51
+ * David Balatero and Paul Dix for [typhoeus](https://github.com/dbalatero/typhoeus)
52
+
53
+ ... and many other contributors. Thanks, guys. You rock!
54
+
data/bin/sapoci-search ADDED
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'optparse'
4
+ require 'ostruct'
5
+ require 'uri'
6
+
7
+ $LOAD_PATH << File.expand_path(File.dirname(__FILE__) + '/../lib')
8
+ require 'sapoci/connect'
9
+ require 'faraday'
10
+ require 'rack'
11
+ require 'sapoci'
12
+ require 'active_support/core_ext'
13
+
14
+ options = OpenStruct.new
15
+ parser = OptionParser.new do |opts|
16
+ opts.on("-d", "--[no-]debug", "Show raw response") do |o|
17
+ options.debug = o
18
+ end
19
+
20
+ opts.on("-p", "--post", "Use POST instead of GET") do |o|
21
+ options.http_post = o
22
+ end
23
+
24
+ opts.separator ""
25
+ opts.separator "Common options:"
26
+
27
+ opts.on_tail("-?", "-h", "--help", "Show this message") do
28
+ puts opts
29
+ exit
30
+ end
31
+ end
32
+
33
+ begin
34
+ parser.parse!(ARGV)
35
+
36
+ # Parameters
37
+ url = ARGV[0]
38
+ keywords = ARGV[1]
39
+
40
+ # Parse URL and query parameters
41
+ uri = URI.parse(url)
42
+ params = Rack::Utils.parse_query(uri.query) if uri.query
43
+ uri.query = nil
44
+
45
+ # Setup
46
+ conn = Faraday.new(uri.to_s, :ssl => {:verify => true}) do |builder|
47
+ builder.use SAPOCI::Connect::Middleware::FollowRedirects
48
+ builder.use SAPOCI::Connect::Middleware::PassCookies
49
+ builder.use SAPOCI::Connect::Middleware::BackgroundSearch
50
+ builder.use Faraday::Response::Logger if options.debug
51
+ builder.adapter :net_http
52
+ end
53
+
54
+ # Execute
55
+ method = options.http_post ? :post : :get
56
+ resp = SAPOCI::Connect.search(method, conn, keywords, "http://return.to/me", params)
57
+ if resp.status == 200
58
+ doc = resp.env[:sapoci]
59
+ $stdout.puts "%3s %-15s %-30s %s" % ["Idx", "Vendormat", "Description", "Price per unit"]
60
+ $stdout.puts "".ljust(98, '-')
61
+ doc.items.each do |item|
62
+ $stdout.puts "%3s %-15s %-30s %10.3f %-3s per %9.2f %-3s" % [item.index, item.vendormat, item.description, item.price, item.currency, item.priceunit, item.unit]
63
+ $stdout.puts " %s" % [item.longtext]
64
+ end
65
+ $stdout.puts "===> #{doc.items.size} items"
66
+ $stdout.puts resp.body.to_s if options.debug
67
+ exit 0
68
+ elsif resp.status == 404
69
+ $stdout.puts "Not found (HTTP status #{resp.status})"
70
+ $stdout.puts resp.body.to_s if options.debug
71
+ exit 1
72
+ elsif resp.status == 500
73
+ $stdout.puts "Server crashed (HTTP status #{resp.status})"
74
+ $stdout.puts resp.body.to_s if options.debug
75
+ exit 1
76
+ else
77
+ $stdout.puts "Error: HTTP status code=#{resp.status}"
78
+ $stdout.puts resp.body.to_s if options.debug
79
+ exit 1
80
+ end
81
+
82
+
83
+ rescue => e
84
+ $stderr.print "#{e.class}: " unless e.class == RuntimeError
85
+ $stderr.puts e.message
86
+ $stderr.puts e.backtrace
87
+ exit 1
88
+ end
89
+
90
+
@@ -0,0 +1,22 @@
1
+ module SAPOCI
2
+ module Connect
3
+ module Middleware
4
+ class BackgroundSearch < Faraday::Response::Middleware
5
+ def initialize(app, options = {})
6
+ @options = options
7
+ super(app)
8
+ end
9
+
10
+ def call(env)
11
+ @app.call(env).on_complete do |resp|
12
+ case env[:status]
13
+ when 200
14
+ env[:sapoci] = SAPOCI::Document.from_html(env[:body])
15
+ else
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,55 @@
1
+ module SAPOCI
2
+ module Connect
3
+ module Middleware
4
+ class RedirectLimitReached < Faraday::Error::ClientError
5
+ attr_reader :response
6
+
7
+ def initialize(response)
8
+ super "too many redirects; last one to: #{response['location']}"
9
+ @response = response
10
+ end
11
+ end
12
+
13
+ class RedirectWithoutLocation < Faraday::Error::ClientError
14
+ attr_reader :response
15
+
16
+ def initialize(response)
17
+ super "redirect without setting HTTP Location header"
18
+ @response = response
19
+ end
20
+ end
21
+
22
+ class FollowRedirects < Faraday::Middleware
23
+ REDIRECTS = [301, 302, 303]
24
+ FOLLOW_LIMIT = 5
25
+
26
+ def initialize(app, options = {})
27
+ super(app)
28
+ @options = options
29
+ @limit = options[:limit] || FOLLOW_LIMIT
30
+ end
31
+
32
+ def call(env)
33
+ process(@app.call(env), @limit)
34
+ end
35
+
36
+ def process(response, limit)
37
+ response.on_complete do |env|
38
+ if redirect?(response)
39
+ raise RedirectLimitReached, response if limit.zero?
40
+ raise RedirectWithoutLocation, response if response['location'].blank?
41
+ env[:url] += response['location']
42
+ env[:method] = :get
43
+ response = process(@app.call(env), limit - 1)
44
+ end
45
+ end
46
+ end
47
+
48
+ def redirect?(response)
49
+ REDIRECTS.include? response.status
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+
@@ -0,0 +1,25 @@
1
+ module SAPOCI
2
+ module Connect
3
+ module Middleware
4
+ class PassCookies < Faraday::Response::Middleware
5
+ def initialize(app, options = {})
6
+ @options = options
7
+ @cookies = []
8
+ super(app)
9
+ end
10
+
11
+ def call(env)
12
+ unless @cookies.empty?
13
+ cookies = @cookies.compact.uniq.join("; ").squeeze(";")
14
+ env[:request_headers]['Cookie'] = cookies
15
+ end
16
+ @app.call(env).on_complete do |resp|
17
+ if cookie = resp[:response_headers]['Set-Cookie']
18
+ @cookies << cookie
19
+ end
20
+ end
21
+ end # call
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,54 @@
1
+ require 'faraday'
2
+ require 'sapoci'
3
+ require 'sapoci/connect/middleware/follow_redirects'
4
+ require 'sapoci/connect/middleware/pass_cookies'
5
+ require 'sapoci/connect/middleware/background_search'
6
+
7
+ module SAPOCI
8
+ module Connect
9
+
10
+ # Perform an OCI background search.
11
+ #
12
+ # If you need to follow redirects and pass cookies along, you should
13
+ # initialize and use Faraday with this pattern:
14
+ #
15
+ # conn = Faraday.new("http://shop.com/path", :params => {"optional" => "value"}) do |builder|
16
+ # builder.use SAPOCI::Connect::Middleware::FollowRedirects
17
+ # builder.use SAPOCI::Connect::Middleware::PassCookies
18
+ # builder.use SAPOCI::Connect::Middleware::BackgroundSearch
19
+ # builder.adapter :net_http
20
+ # end
21
+ # conn.options[:timeout] = 3
22
+ # conn.options[:open_timeout] = 5
23
+ # resp = SAPOCI::Connect.search(:get, conn, "toner", "http://return.to/me")
24
+ # puts resp.status # => 200
25
+ # puts resp.body # => <SAPOCI::Document>
26
+ #
27
+ def self.search(method, connection, keywords, hook_url, extra_params = nil)
28
+ params = {
29
+ "FUNCTION" => "BACKGROUND_SEARCH",
30
+ "SEARCHSTRING" => keywords,
31
+ "HOOK_URL" => hook_url
32
+ }
33
+ params.update(extra_params) if extra_params
34
+
35
+ unless connection.builder.handlers.include?(SAPOCI::Connect::Middleware::BackgroundSearch)
36
+ connection.use SAPOCI::Connect::Middleware::BackgroundSearch
37
+ end
38
+
39
+ case method.to_sym
40
+ when :get
41
+ connection.get do |req|
42
+ req.params = params
43
+ end
44
+ when :post
45
+ connection.post do |req|
46
+ req.body = Faraday::Utils.build_nested_query params
47
+ end
48
+ else
49
+ raise "SAPOCI::Connect.search only allows :get or :post requests"
50
+ end
51
+ end
52
+
53
+ end
54
+ end
metadata ADDED
@@ -0,0 +1,171 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sapoci-connect
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.7
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Oliver Eilhard
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-10-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: faraday
16
+ requirement: &70144890289320 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.7.4
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70144890289320
25
+ - !ruby/object:Gem::Dependency
26
+ name: em-synchrony
27
+ requirement: &70144890288740 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70144890288740
36
+ - !ruby/object:Gem::Dependency
37
+ name: em-http-request
38
+ requirement: &70144890288140 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 1.0.0
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70144890288140
47
+ - !ruby/object:Gem::Dependency
48
+ name: typhoeus
49
+ requirement: &70144890287460 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.2.4
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *70144890287460
58
+ - !ruby/object:Gem::Dependency
59
+ name: rack
60
+ requirement: &70144890286820 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: 1.1.0
66
+ - - <
67
+ - !ruby/object:Gem::Version
68
+ version: '2'
69
+ type: :runtime
70
+ prerelease: false
71
+ version_requirements: *70144890286820
72
+ - !ruby/object:Gem::Dependency
73
+ name: sapoci
74
+ requirement: &70144890285840 !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: 0.1.4
80
+ type: :runtime
81
+ prerelease: false
82
+ version_requirements: *70144890285840
83
+ - !ruby/object:Gem::Dependency
84
+ name: bundler
85
+ requirement: &70144890285160 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ~>
89
+ - !ruby/object:Gem::Version
90
+ version: '1.0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: *70144890285160
94
+ - !ruby/object:Gem::Dependency
95
+ name: rdoc
96
+ requirement: &70144890284560 !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: '2.5'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: *70144890284560
105
+ - !ruby/object:Gem::Dependency
106
+ name: rake
107
+ requirement: &70144890283900 !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ! '>='
111
+ - !ruby/object:Gem::Version
112
+ version: 0.9.2
113
+ type: :development
114
+ prerelease: false
115
+ version_requirements: *70144890283900
116
+ - !ruby/object:Gem::Dependency
117
+ name: sinatra
118
+ requirement: &70144890283300 !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ~>
122
+ - !ruby/object:Gem::Version
123
+ version: '1.2'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: *70144890283300
127
+ description: HTTP client library for working with SAP OCI compliant servers.
128
+ email:
129
+ - oliver.eilhard@gmail.com
130
+ executables:
131
+ - sapoci-search
132
+ extensions: []
133
+ extra_rdoc_files:
134
+ - CHANGELOG.md
135
+ - LICENSE
136
+ - README.md
137
+ files:
138
+ - bin/sapoci-search
139
+ - lib/sapoci/connect.rb
140
+ - lib/sapoci/connect/middleware/background_search.rb
141
+ - lib/sapoci/connect/middleware/follow_redirects.rb
142
+ - lib/sapoci/connect/middleware/pass_cookies.rb
143
+ - CHANGELOG.md
144
+ - LICENSE
145
+ - README.md
146
+ homepage: http://github.com/meplato/sapoci-connect
147
+ licenses: []
148
+ post_install_message:
149
+ rdoc_options:
150
+ - --charset=UTF-8
151
+ require_paths:
152
+ - lib
153
+ required_ruby_version: !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ! '>='
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ required_rubygems_version: !ruby/object:Gem::Requirement
160
+ none: false
161
+ requirements:
162
+ - - ! '>='
163
+ - !ruby/object:Gem::Version
164
+ version: 1.3.6
165
+ requirements: []
166
+ rubyforge_project:
167
+ rubygems_version: 1.8.9
168
+ signing_key:
169
+ specification_version: 3
170
+ summary: HTTP client library for working with SAP OCI compliant servers.
171
+ test_files: []