sean-rets 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 679f076c80dc81f0dc15aecb394ff3435250244f
4
+ data.tar.gz: 4c287ca2d5ed9e28617cc3890701fa7e5d41707c
5
+ SHA512:
6
+ metadata.gz: fcdde80697677da90f2952749b1259e88cee217c11f2b2a122584bf55424dc8defe9f782f0d03262d5a448dbcc0afcb570277831543af028dbcfa117c5426dd9
7
+ data.tar.gz: 0192696920f4fa35c48139503dc0db6d762b7902603555b401398d545ea8733a8c4c07efa2653f186113bfc6335b3a5f339f042b49a15e06145a31e4529172b5
File without changes
@@ -0,0 +1,89 @@
1
+ ### 0.6.0 / 2013-10-30
2
+
3
+ * fix: fix spelling error that created misleading exceptions
4
+ * feature: track stats for http requests sent
5
+ * feature: raise an exception if the login action doesn't return an http 200 status
6
+ * feature: add better class description and more fields to print tree
7
+ * feature: support http proxies
8
+ * feature: customizable http timeouts
9
+ * feature: add logging http headers when in debug mode
10
+ * feature: strip invalid utf8 from responses before parsing
11
+ * fix: don't raise an exception on a 401 after logout
12
+ * fix: treat no matching records status without a count node as a zero count
13
+ * feature: add an option for loading custom ca_certs
14
+ * feature: remove invalid resource types from metadata
15
+ * feature: special case http 412
16
+ * feature: add max_retries option
17
+
18
+ ### 0.5.1 / 2013-10-30
19
+
20
+ * fix: 0.5.0 was broken, fix gem Manifest to fix gem
21
+
22
+ ### 0.5.0 / 2013-09-05
23
+
24
+ * feature: Allow client.count to get integer count
25
+ * feature: Allow for downcased capability names
26
+ * fix: Handle the rets element being empty
27
+ * feature: Instrument rets client with stats reporting
28
+ * feature: Add a locking client
29
+ * feature: Support Basic Authentication
30
+
31
+ ### 0.4.0 / 2012-08-29
32
+
33
+ * fix: update authentication header to uri matches path
34
+
35
+ ### 0.3.0 / 2012-07-31
36
+
37
+ * correctly handle digest authentication
38
+
39
+ ### 0.3.0.rc.0 / 2012-07-26
40
+
41
+ * feature: significantly better handling of authorization failures
42
+
43
+ ### 0.2.1 / 2012-04-20
44
+
45
+ * fix: better handling of malformed RETS responses
46
+
47
+ ### 0.2.0 / 2012-04-20
48
+
49
+ * feature: Ruby 1.9 compatibility!
50
+
51
+ ### 0.1.7 / 2012-04-05
52
+
53
+ * feature: key_field lookup for resources
54
+
55
+ ### 0.1.6 / 2012-04-03
56
+
57
+ * fix: user_agent authentication
58
+
59
+ ### 0.1.5 / 2012-03-17
60
+
61
+ * fix: retries raise error after too many failures
62
+ * fix: raise error for failed multipart object request
63
+ * fix: retries start with a clean slate, fixing authorization errors during retry
64
+
65
+ ### 0.1.4 / 2012-03-12
66
+
67
+ * fix: an MLS uses lower case in RETS tag
68
+
69
+ ### 0.1.3 / 2012-03-05
70
+
71
+ * fixes to support location=1 in getobject query
72
+
73
+ ### 0.1.2 / 2012-02-17
74
+
75
+ * bugfix - check ReplyCode in login, retry on errors
76
+
77
+ ### 0.1.1 / 2012-01-11
78
+
79
+ * bugfix - prevent infinite loop in login
80
+
81
+ # rets Changelog
82
+
83
+ ### 0.1.0 / 2011-06-23
84
+
85
+ * First public release!
86
+
87
+ ### 0.0.1 / 2011-03-24
88
+
89
+ * Project Created
@@ -0,0 +1,28 @@
1
+ CHANGELOG.md
2
+ Manifest.txt
3
+ README.md
4
+ Rakefile
5
+ bin/rets
6
+ lib/rets.rb
7
+ lib/rets/client.rb
8
+ lib/rets/client_progress_reporter.rb
9
+ lib/rets/http_client.rb
10
+ lib/rets/locking_http_client.rb
11
+ lib/rets/measuring_http_client.rb
12
+ lib/rets/metadata.rb
13
+ lib/rets/metadata/containers.rb
14
+ lib/rets/metadata/lookup_type.rb
15
+ lib/rets/metadata/resource.rb
16
+ lib/rets/metadata/rets_class.rb
17
+ lib/rets/metadata/root.rb
18
+ lib/rets/metadata/table.rb
19
+ lib/rets/parser/compact.rb
20
+ lib/rets/parser/multipart.rb
21
+ test/fixtures.rb
22
+ test/helper.rb
23
+ test/test_client.rb
24
+ test/test_locking_http_client.rb
25
+ test/test_metadata.rb
26
+ test/test_parser_compact.rb
27
+ test/test_parser_multipart.rb
28
+ test/vcr_cassettes/unauthorized_response.yml
@@ -0,0 +1,47 @@
1
+ # rets
2
+
3
+ * http://github.com/estately/rets
4
+
5
+ ## DESCRIPTION:
6
+
7
+ [![Build Status](https://secure.travis-ci.org/estately/rets.png?branch=master)](http://travis-ci.org/estately/rets)
8
+ A pure-ruby library for fetching data from [RETS] servers.
9
+
10
+ [RETS]: http://www.rets.org
11
+
12
+ ## REQUIREMENTS:
13
+
14
+ * [net-http-persistent]
15
+ * [nokogiri]
16
+
17
+ [net-http-persistent]: http://seattlerb.rubyforge.org/net-http-persistent/
18
+ [nokogiri]: http://nokogiri.org
19
+
20
+ ## EXAMPLE USAGE:
21
+
22
+ We need work in this area! There are currently a few guideline examples in the `example` folder on connecting, fetching a property's data, and fetching a property's photos.
23
+
24
+ ## LICENSE:
25
+
26
+ (The MIT License)
27
+
28
+ Copyright (c) 2011 Estately, Inc. <opensource@estately.com>
29
+
30
+ Permission is hereby granted, free of charge, to any person obtaining
31
+ a copy of this software and associated documentation files (the
32
+ 'Software'), to deal in the Software without restriction, including
33
+ without limitation the rights to use, copy, modify, merge, publish,
34
+ distribute, sublicense, and/or sell copies of the Software, and to
35
+ permit persons to whom the Software is furnished to do so, subject to
36
+ the following conditions:
37
+
38
+ The above copyright notice and this permission notice shall be included
39
+ in all copies or substantial portions of the Software.
40
+
41
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
42
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
43
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
44
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
45
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
46
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
47
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,27 @@
1
+ require 'rubygems'
2
+ require 'hoe'
3
+ require 'rake/testtask'
4
+
5
+ Hoe.plugin :git, :doofus
6
+ Hoe.plugin :travis
7
+ Hoe.plugin :gemspec
8
+
9
+ Hoe.spec 'rets' do
10
+ developer 'Estately, Inc. Open Source', 'opensource@estately.com'
11
+
12
+ extra_deps << [ "httpclient", "~> 2.3.0" ]
13
+ extra_deps << [ "nokogiri", "~> 1.5.2" ]
14
+
15
+ extra_dev_deps << [ "mocha", "~> 0.11.0" ]
16
+ extra_dev_deps << [ "vcr", "~> 2.2.2" ]
17
+ extra_dev_deps << [ "webmock", "~> 1.8.0" ]
18
+
19
+ ### Use markdown for changelog and readme
20
+ self.history_file = 'CHANGELOG.md'
21
+ self.readme_file = 'README.md'
22
+ end
23
+
24
+
25
+ Rake::TestTask.new do |t|
26
+ t.pattern = "test/test_*.rb"
27
+ end
@@ -0,0 +1,202 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "optparse"
4
+ require "pp"
5
+
6
+ require "rubygems"
7
+
8
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
9
+ require "rets"
10
+
11
+ class RetsCli
12
+ def self.parse(args)
13
+
14
+ actions = %w(metadata search count object)
15
+ options = {:count => 5}
16
+
17
+ opts = OptionParser.new do |opts|
18
+ opts.banner = "Usage: #{File.basename($0)} URL [options] [query]"
19
+
20
+ opts.separator ""
21
+ opts.separator "Authentication options:"
22
+
23
+ opts.on("-U", "--username USERNAME", "The username to authenticate with.") do |username|
24
+ options[:username] = username
25
+ end
26
+
27
+ opts.on("-P", "--password [PASSWORD]", "The password to authenticate with.","Prompts if no argument is provided.") do |password|
28
+ options[:password] = password #or prompt # TODO
29
+ end
30
+
31
+ opts.on("-A", "--agent AGENT", "User-Agent header to provide.") do |agent|
32
+ options[:agent] = agent
33
+ end
34
+
35
+ opts.on("-B", "--agent-password [PASSWORD]", "User-Agent password to provide.") do |ua_password|
36
+ options[:ua_password] = ua_password
37
+ end
38
+
39
+ opts.separator ""
40
+ opts.separator "Actions:"
41
+
42
+ opts.on("-p", "--capabilities", "Print capabilities of the RETS server.") do |capabilities|
43
+ options[:capabilities] = capabilities
44
+ end
45
+
46
+ opts.on("-a", "--action ACTION", actions, "Action to perform (#{actions.join(",")}).") do |action|
47
+ options[:action] = action
48
+ end
49
+
50
+ opts.on("-m", "--metadata [FORMAT]", %w(tree long short), "Print metadata.", "Format is short, long or tree.", "Defaults to short.") do |format|
51
+ options[:action] = "metadata"
52
+ options[:metadata_format] = format || "short"
53
+ end
54
+
55
+ opts.separator ""
56
+ opts.separator "Search action options:"
57
+
58
+ opts.on("-r", "--resource NAME", "Name of resource to search for.") do |name|
59
+ options[:resource] = name
60
+ end
61
+
62
+ opts.on("-c", "--class NAME", "Name of class to search for.") do |name|
63
+ options[:class] = name
64
+ end
65
+
66
+ opts.on("-n", "--number LIMIT", Integer, "Return LIMIT results. Defaults to 5.") do |limit|
67
+ options[:limit] = limit
68
+ end
69
+
70
+ opts.separator ""
71
+ opts.separator "Misc options:"
72
+
73
+ opts.on_tail("-v", "--verbose", "Be verbose.") do |verbose|
74
+ logger = Class.new do
75
+ def method_missing(method, *a, &b)
76
+ puts a
77
+ end
78
+ end
79
+
80
+ options[:logger] = logger.new
81
+ end
82
+
83
+ opts.on_tail("-h", "--help", "Show this message") do
84
+ puts opts
85
+ exit
86
+ end
87
+
88
+ opts.on_tail("--version", "Show version") do
89
+ puts Rets::VERSION
90
+ exit
91
+ end
92
+
93
+ end
94
+
95
+ begin
96
+ opts.parse!(args.empty? ? ["-h"] : args)
97
+ rescue OptionParser::InvalidArgument => e
98
+ abort e.message
99
+ end
100
+
101
+ options
102
+ end
103
+
104
+ end
105
+
106
+ options = RetsCli.parse(ARGV)
107
+ url = ARGV[0] or abort "Need login URL"
108
+ query = ARGV[1]
109
+
110
+ client = Rets::Client.new(options.merge(:login_url => url))
111
+
112
+ if options[:capabilities]
113
+ pp client.capabilities
114
+ end
115
+
116
+ case options[:action]
117
+ when "metadata" then
118
+ metadata = client.metadata
119
+
120
+ if options[:metadata_format] != "tree"
121
+ preferred_fields = %w(ClassName SystemName ResourceID StandardName VisibleName MetadataEntryID KeyField)
122
+
123
+
124
+ # All types except system
125
+ types = Rets::METADATA_TYPES.map { |t| t.downcase.to_sym } - [:system]
126
+
127
+ types.each do |type|
128
+ # if RowContainer ...
129
+ rows = metadata[type]
130
+
131
+ puts type.to_s.capitalize
132
+ puts "="*40
133
+
134
+ print_key_value = lambda do |k,v|
135
+ key = "#{k}:".ljust(35)
136
+ value = "#{v}".ljust(35)
137
+
138
+ puts [key, value].join
139
+ end
140
+
141
+ rows.each do |row|
142
+ top, rest = row.partition { |k,v| preferred_fields.include?(k) }
143
+
144
+ top.each(&print_key_value)
145
+
146
+ rest.sort_by{|k,v|k}.each(&print_key_value) if options[:metadata_format] == "long"
147
+
148
+ puts
149
+ end
150
+
151
+ puts
152
+ end
153
+
154
+ # Tree format
155
+ else
156
+ metadata.print_tree
157
+ end
158
+
159
+ when "search" then
160
+ pp client.find(:all,
161
+ :search_type => options[:resource],
162
+ :class => options[:class],
163
+ :query => query,
164
+ :count => Rets::Client::COUNT.exclude,
165
+ :limit => options[:limit])
166
+
167
+ when "count" then
168
+ pp client.find(:all,
169
+ :search_type => options[:resource],
170
+ :class => options[:class],
171
+ :query => query,
172
+ :count => Rets::Client::COUNT.only,
173
+ :limit => options[:limit])
174
+
175
+ when "object" then
176
+
177
+ def write_objects(parts)
178
+ parts.each do |part|
179
+ cid = part.headers["content-id"].to_i
180
+ oid = part.headers["object-id"].to_i
181
+
182
+ File.open("tmp/#{cid}-#{oid}", "wb") do |f|
183
+ puts f.path
184
+
185
+ f.write part.body
186
+ end
187
+ end
188
+ end
189
+
190
+ parts = client.all_objects(
191
+ :resource => "Property",
192
+ :resource_id => 90020062739, # id from KeyField for a given property
193
+ :object_type => "Photo"
194
+ )
195
+
196
+ parts.each { |pt| p pt.headers }
197
+
198
+ write_objects(parts)
199
+
200
+ end
201
+
202
+ client.logout
@@ -0,0 +1,45 @@
1
+ require 'uri'
2
+ require 'digest/md5'
3
+ require 'nokogiri'
4
+
5
+ module Rets
6
+ VERSION = '0.6.0'
7
+
8
+ MalformedResponse = Class.new(ArgumentError)
9
+ UnknownResponse = Class.new(ArgumentError)
10
+ NoLogout = Class.new(ArgumentError)
11
+
12
+ class AuthorizationFailure < ArgumentError
13
+ attr_reader :status, :body
14
+ def initialize(status, body)
15
+ @status = status
16
+ @body = body
17
+ super("HTTP status: #{status} (#{body})")
18
+ end
19
+ end
20
+
21
+ class InvalidRequest < ArgumentError
22
+ attr_reader :error_code, :reply_text
23
+ def initialize(error_code, reply_text)
24
+ @error_code = error_code
25
+ @reply_text = reply_text
26
+ super("Got error code #{error_code} (#{reply_text})")
27
+ end
28
+ end
29
+
30
+ class UnknownCapability < ArgumentError
31
+ attr_reader :capability_name
32
+ def initialize(capability_name)
33
+ @capability_name = capability_name
34
+ super("unknown capability #{capability_name}")
35
+ end
36
+ end
37
+ end
38
+
39
+ require 'rets/client'
40
+ require 'rets/metadata'
41
+ require 'rets/parser/compact'
42
+ require 'rets/parser/multipart'
43
+ require 'rets/measuring_http_client'
44
+ require 'rets/locking_http_client'
45
+ require 'rets/client_progress_reporter'