obarc 0.5.2

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.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +19 -0
  3. data/.gitignore +5 -0
  4. data/.rubocop.yml +1156 -0
  5. data/.travis.yml +12 -0
  6. data/Gemfile +3 -0
  7. data/Gemfile.lock +78 -0
  8. data/README.md +133 -0
  9. data/Rakefile +39 -0
  10. data/doc/OBarc.html +210 -0
  11. data/doc/OBarc/Api.html +883 -0
  12. data/doc/OBarc/Session.html +5399 -0
  13. data/doc/OBarc/Utils.html +117 -0
  14. data/doc/OBarc/Utils/Exceptions.html +115 -0
  15. data/doc/OBarc/Utils/Exceptions/InvalidArgumentError.html +230 -0
  16. data/doc/OBarc/Utils/Exceptions/InvalidElementError.html +218 -0
  17. data/doc/OBarc/Utils/Exceptions/InvalidWordError.html +218 -0
  18. data/doc/OBarc/Utils/Exceptions/MissingArgumentError.html +230 -0
  19. data/doc/OBarc/Utils/Exceptions/OBarcArgumentError.html +151 -0
  20. data/doc/OBarc/Utils/Exceptions/OBarcError.html +291 -0
  21. data/doc/OBarc/Utils/Exceptions/OBarcResponseError.html +520 -0
  22. data/doc/OBarc/Utils/Exceptions/OverLimitError.html +218 -0
  23. data/doc/OBarc/Utils/Exceptions/TimeOutError.html +218 -0
  24. data/doc/OBarc/Utils/Helper.html +115 -0
  25. data/doc/OBarc/Utils/Helper/ObjectExtensions.html +105 -0
  26. data/doc/_index.html +239 -0
  27. data/doc/class_list.html +58 -0
  28. data/doc/css/common.css +1 -0
  29. data/doc/css/full_list.css +57 -0
  30. data/doc/css/style.css +339 -0
  31. data/doc/file.README.html +229 -0
  32. data/doc/file_list.html +60 -0
  33. data/doc/frames.html +26 -0
  34. data/doc/index.html +229 -0
  35. data/doc/js/app.js +219 -0
  36. data/doc/js/full_list.js +181 -0
  37. data/doc/js/jquery.js +4 -0
  38. data/doc/method_list.html +465 -0
  39. data/doc/top-level-namespace.html +112 -0
  40. data/graphics/obarc-logo.png +0 -0
  41. data/graphics/obarc-logo.xcf +0 -0
  42. data/lib/obarc.rb +14 -0
  43. data/lib/obarc/api.rb +220 -0
  44. data/lib/obarc/session.rb +514 -0
  45. data/lib/obarc/utils/exceptions.rb +35 -0
  46. data/lib/obarc/utils/helper.rb +18 -0
  47. data/lib/obarc/version.rb +3 -0
  48. data/obarc.gemspec +32 -0
  49. metadata +276 -0
@@ -0,0 +1,112 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
+ <title>
7
+ Top Level Namespace
8
+
9
+ &mdash; Documentation by YARD 0.8.7.6
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
16
+
17
+ <script type="text/javascript" charset="utf-8">
18
+ hasFrames = window.top.frames.main ? true : false;
19
+ relpath = '';
20
+ framesUrl = "frames.html#!top-level-namespace.html";
21
+ </script>
22
+
23
+
24
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
25
+
26
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
27
+
28
+
29
+ </head>
30
+ <body>
31
+ <div id="header">
32
+ <div id="menu">
33
+
34
+ <a href="_index.html">Index</a> &raquo;
35
+
36
+
37
+ <span class="title">Top Level Namespace</span>
38
+
39
+
40
+ <div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
41
+ </div>
42
+
43
+ <div id="search">
44
+
45
+ <a class="full_list_link" id="class_list_link"
46
+ href="class_list.html">
47
+ Class List
48
+ </a>
49
+
50
+ <a class="full_list_link" id="method_list_link"
51
+ href="method_list.html">
52
+ Method List
53
+ </a>
54
+
55
+ <a class="full_list_link" id="file_list_link"
56
+ href="file_list.html">
57
+ File List
58
+ </a>
59
+
60
+ </div>
61
+ <div class="clear"></div>
62
+ </div>
63
+
64
+ <iframe id="search_frame"></iframe>
65
+
66
+ <div id="content"><h1>Top Level Namespace
67
+
68
+
69
+
70
+ </h1>
71
+
72
+ <dl class="box">
73
+
74
+
75
+
76
+
77
+
78
+
79
+
80
+
81
+ </dl>
82
+ <div class="clear"></div>
83
+
84
+ <h2>Defined Under Namespace</h2>
85
+ <p class="children">
86
+
87
+
88
+ <strong class="modules">Modules:</strong> <span class='object_link'><a href="OBarc.html" title="OBarc (module)">OBarc</a></span>
89
+
90
+
91
+
92
+
93
+ </p>
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+ </div>
104
+
105
+ <div id="footer">
106
+ Generated on Tue Apr 4 17:29:29 2017 by
107
+ <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
108
+ 0.8.7.6 (ruby-2.2.5).
109
+ </div>
110
+
111
+ </body>
112
+ </html>
Binary file
Binary file
@@ -0,0 +1,14 @@
1
+ require 'obarc/version'
2
+ require 'json'
3
+ require 'rest-client'
4
+
5
+ module OBarc
6
+ require 'obarc/utils/helper'
7
+ require 'obarc/session'
8
+ extend self
9
+
10
+ def login!(options)
11
+ options[:base_url] ||= "#{options[:protocol]}://#{options[:server_host]}:#{options[:server_port]}/api/#{options[:api_version]}"
12
+ Session.new(username: options[:username], password: options[:password], cookies: Api.post_login(options).cookies)
13
+ end
14
+ end
@@ -0,0 +1,220 @@
1
+ require 'obarc/utils/helper'
2
+ require 'obarc/utils/exceptions'
3
+ require 'uri'
4
+ require 'base64'
5
+
6
+ module OBarc
7
+ module Api
8
+ extend self
9
+ using Utils::Helper::ObjectExtensions
10
+
11
+ DEFAULT_TIMEOUT = 60 * 60 * 1
12
+
13
+ VALID_ACTIONS = {
14
+ get: %i(image profile listings followers following contracts shutdown
15
+ settings connected_peers routing_table notifications chat_messages
16
+ chat_conversations sales purchases order cases order_messages ratings
17
+ btc_price),
18
+ post: %i(login follow unfollow profile social_accounts
19
+ contract make_moderator unmake_moderator purchase_contract
20
+ confirm_order upload_image complete_order settings
21
+ mark_notification_as_read broadcast mark_chat_message_as_read
22
+ check_for_payment dispute_contract close_dispute release_funds refund
23
+ mark_discussion_as_read),
24
+ delete: %i(social_accounts contract chat_conversation)
25
+ }.freeze
26
+
27
+ # POST api/v1/login
28
+ def post_login(options = {})
29
+ url = "#{build_base_url(options)}/login"
30
+ auth = build_authentication(options)
31
+
32
+ raise Utils::Exceptions::MissingArgumentError, [:username, :password] if auth.empty?
33
+
34
+ execute method: :post, url: url, headers: {params: auth},
35
+ verify_ssl: build_verify_ssl(options)
36
+ end
37
+
38
+ def ping(options = {})
39
+ execute(method: :get,
40
+ url: "#{build_base_url(options)}/connected_peers?_=#{Time.now.to_i}",
41
+ headers: build_headers(options), verify_ssl: build_verify_ssl(options))
42
+ end
43
+
44
+ def respond_to_missing?(m, include_private = false)
45
+ verb = m.to_s.split('_')
46
+ rest_method = verb[0].to_sym
47
+ return false unless VALID_ACTIONS.keys.include?(rest_method)
48
+
49
+ endpoint = verb[1..-1].join('_')
50
+ return false if endpoint.nil?
51
+
52
+ VALID_ACTIONS[rest_method].include?(endpoint.to_sym)
53
+ end
54
+
55
+ def method_missing(m, *args, &block)
56
+ super unless respond_to_missing?(m)
57
+
58
+ # Many of the calls to restapi.py are uniform enough for DRY code, but the
59
+ # ones that aren't are mapped here.
60
+
61
+ rest_method, endpoint, params, options = case m
62
+ when :get_image then [:get, 'get_image', args[0], args[1]]
63
+ when :get_listings then [:get, 'get_listings', args[0], args[1]]
64
+ when :get_followers then [:get, 'get_followers', args[0], args[1]]
65
+ when :get_following then [:get, 'get_following', args[0], args[1]]
66
+ when :post_contract then [:post, 'contracts', args[0], args[1]]
67
+ when :delete_contract then [:delete, 'contracts', args[0], args[1]]
68
+ when :get_notifications then [:get, 'get_notifications', nil, args[0]]
69
+ when :get_chat_conversations then [:get, 'get_chat_conversations', nil, args[0]]
70
+ when :get_sales then [:get, 'get_sales', nil, args[0]]
71
+ when :get_purchases then [:get, 'get_purchases', nil, args[0]]
72
+ when :get_cases then [:get, 'get_cases', nil, args[0]]
73
+ when :get_ratings then [:get, 'get_ratings', args[0], args[1]]
74
+ else
75
+ verb = m.to_s.split('_')
76
+ a = [verb[0].to_sym, verb[1..-1].join('_')]
77
+ a << if args.size == 1
78
+ nil
79
+ else
80
+ args[0]
81
+ end
82
+ a << args[args.size - 1]
83
+ end
84
+
85
+ url = "#{build_base_url(options)}/#{endpoint}" if !!endpoint && !!options
86
+ if !!rest_method && !!url && !!options
87
+ headers = build_headers(options)
88
+ headers = headers.merge(params: params.compact) if !!params
89
+ return execute method: rest_method, url: url, headers: headers,
90
+ verify_ssl: build_verify_ssl(options)
91
+ end
92
+
93
+ raise Utils::Exceptions::OBarcError, "Did not handle #{m} as expected, arguments: #{args}"
94
+ end
95
+
96
+ # POST api/v1/upload_image
97
+ def post_upload_image(options = {})
98
+ elements = [:image, :avatar, :header]
99
+ params = options.slice(*elements)
100
+ options = options.delete_if { |k, v| elements.include? k }
101
+
102
+ url = "#{build_base_url(options)}/upload_images"
103
+ execute method: :post, url: url,
104
+ headers: build_headers(options).merge(params: params.compact),
105
+ verify_ssl: build_verify_ssl(options)
106
+ end
107
+
108
+ # GET api/v1/contracts
109
+ def get_contracts(contracts, options = {})
110
+ id = contracts[:id]
111
+ guid = contracts[:guid]
112
+
113
+ if !!id && id.size != 40
114
+ raise Utils::Exceptions::InvalidArgumentError, id: "must be 40 characters, if present (was: #{id.size})"
115
+ elsif !!guid && guid.size != 40
116
+ raise Utils::Exceptions::InvalidArgumentError, guid: "must be 40 characters, if present (was: #{guid.size})"
117
+ end
118
+
119
+ url = "#{build_base_url(options)}/contracts"
120
+ execute method: :get, url: url,
121
+ headers: build_headers(options).merge(params: contracts.compact),
122
+ verify_ssl: build_verify_ssl(options)
123
+ end
124
+
125
+ # GET api/v1/get_chat_messages
126
+ def get_chat_messages(chat_messages, options = {})
127
+ guid = chat_messages[:guid]
128
+
129
+ if guid.nil? || guid.size != 40
130
+ raise Utils::Exceptions::InvalidArgumentError, guid: "must be present, 40 characters (was: #{guid.inspect})"
131
+ end
132
+
133
+ url = "#{build_base_url(options)}/get_chat_messages"
134
+ execute method: :get, url: url,
135
+ headers: build_headers(options).merge(params: chat_messages.compact),
136
+ verify_ssl: build_verify_ssl(options)
137
+ end
138
+
139
+ # GET api/v1/get_order
140
+ def get_order(order, options = {})
141
+ order_id = order[:order_id]
142
+
143
+ if order_id.nil?
144
+ raise Utils::Exceptions::InvalidArgumentError, order_id: 'must be present'
145
+ end
146
+
147
+ url = "#{build_base_url(options)}/get_order"
148
+ execute method: :get, url: url,
149
+ headers: build_headers(options).merge(params: order.compact),
150
+ verify_ssl: build_verify_ssl(options)
151
+ end
152
+ private
153
+ def execute(options = {})
154
+ if options[:method] == :post
155
+ options[:headers][:content_type] = 'application/x-www-form-urlencoded'
156
+ end
157
+
158
+ if !!options[:headers][:params]
159
+ params = options[:headers].delete(:params)
160
+
161
+ if params.values.map(&:class).include? Array
162
+ # Dropping to a lower level for parameters since they're more
163
+ # complicated due to the presense of an Array. Note that these
164
+ # parameters go # outside the header.
165
+ options[:url] += "?#{URI::encode_www_form params}"
166
+ elsif params.values.map(&:class).any? { |c| [Tempfile, File, StringIO].include?(c) }
167
+ # Handling (possibly) large files.
168
+ options[:payload] = {multipart: true}
169
+ params.each do |k, v|
170
+ if v.respond_to? :read
171
+ options[:payload][k] = Base64.strict_encode64(v.read)
172
+ else
173
+ options[:payload][k] = v
174
+ # FIXME Might want to warn that we are possibly mixing multipart
175
+ # with simple payload.
176
+ end
177
+ end
178
+ else
179
+ options[:headers][:params] = params
180
+ end
181
+ end
182
+
183
+ RestClient::Request.execute(options.merge(timeout: DEFAULT_TIMEOUT))
184
+ end
185
+
186
+ def build_authentication(options = {})
187
+ if options.kind_of? Session
188
+ {username: options.username, password: options.password}
189
+ else
190
+ options.slice(:username, :password)
191
+ end.compact
192
+ end
193
+
194
+ def build_base_url(options = {})
195
+ if options.kind_of? Session
196
+ options.base_url
197
+ elsif options.kind_of? Hash
198
+ options[:base_url]
199
+ else
200
+ raise Utils::Exceptions::OBarcError, "Unable to build base URL using: #{options.inspect}, expected a OBarc::Session or Hash."
201
+ end
202
+ end
203
+
204
+ def build_headers(options = {})
205
+ if options.kind_of? Session
206
+ {cookies: options.cookies}
207
+ else
208
+ options.slice(:cookies)
209
+ end
210
+ end
211
+
212
+ def build_verify_ssl(options = {})
213
+ if options.kind_of? Session
214
+ !!options.verify_ssl
215
+ else
216
+ !!options[:verify_ssl]
217
+ end
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,514 @@
1
+ require 'obarc/api'
2
+ require 'open-uri'
3
+ require 'logging'
4
+
5
+ module OBarc
6
+ class Session
7
+ OPTIONS_KEYS = %i(protocol server_host server_port api_version username
8
+ password base_url logger cookies verify_ssl)
9
+
10
+ attr_accessor :cookies, :username, :password, :verify_ssl
11
+ attr_writer :base_url, :logger
12
+
13
+ DEFAULT_OPTIONS = {
14
+ protocol: 'http',
15
+ server_host: 'localhost',
16
+ server_port: '18469',
17
+ api_version: 'v1',
18
+ verify_ssl: true
19
+ }
20
+
21
+ def initialize(options = {})
22
+ OPTIONS_KEYS.each do |k|
23
+ value = if options.key?(k)
24
+ options[k]
25
+ else
26
+ DEFAULT_OPTIONS[k]
27
+ end
28
+
29
+ instance_variable_set "@#{k}".to_sym, value
30
+ end
31
+
32
+ @base_url ||= base_url
33
+ @logger ||= logger
34
+ @cookies ||= Api::post_login(self).cookies
35
+ end
36
+
37
+ def base_url
38
+ @base_url ||= "#{@protocol}://#{@server_host}:#{@server_port}/api/#{@api_version}"
39
+ end
40
+
41
+ def logger
42
+ @logger ||= Logging.logger(STDOUT)
43
+ end
44
+
45
+ # Check if there's a valid session.
46
+ #
47
+ # @return [Boolean] True if the session is valid.
48
+ def ping
49
+ return false if !(json = Api::ping(self))
50
+ !!JSON[json]['num_peers']
51
+ rescue RestClient::Unauthorized => e
52
+ logger.warn(e)
53
+ false
54
+ end
55
+
56
+ # Returns the image for the hash specified.
57
+ # @param image [Hash] containing the hash: of the target image, required
58
+ # @return [Object] The image will be returned in .jpg format.
59
+ # @see https://gist.github.com/drwasho/742505589f62f6aa98b4#get-image
60
+ def image(image); Api::get_image(image, self); end
61
+
62
+ # Returns the profile data of the user’s node, or that of a target node.
63
+ #
64
+ # @param profile [Hash] containing the guid: of the target node, optional
65
+ # * The global unique identifier (guid; 40 character hex string) of the node to get the profile data from
66
+ # * If the guid is omitted, your own node’s profile will be returned
67
+ # @return [Hash]
68
+ # @see https://gist.github.com/drwasho/742505589f62f6aa98b4#get-profile
69
+ def profile(profile = nil); JSON[Api::get_profile(profile, self)]; end
70
+
71
+ # Returns just the profile's social accounts of the user’s node, or that of a target node.
72
+ #
73
+ # @param profile [Hash] containing the guid: of the target node, optional
74
+ # * The global unique identifier (guid; 40 character hex string) of the node to get the profile data from
75
+ # * If the guid is omitted, your own node’s social accounts will be returned
76
+ # @return [Hash]
77
+ # @see https://gist.github.com/drwasho/742505589f62f6aa98b4#get-profile
78
+ def social_accounts(profile = nil)
79
+ result = JSON[Api::get_profile(profile, self)]
80
+
81
+ if !!result && !!result['profile'] && !!result['profile']['social_accounts']
82
+ result['profile']['social_accounts']
83
+ else
84
+ []
85
+ end
86
+ end
87
+
88
+ # Returns the listings of the user’s node, or that of a target node.
89
+ #
90
+ # @param listings [Hash] containing the guid: of the target node, optional
91
+ # * If the guid is omitted, the server will look for listings in your own node’s database.
92
+ # @return [Hash]
93
+ # @see https://gist.github.com/drwasho/742505589f62f6aa98b4#get-get_listings
94
+ def listings(listings = nil); JSON[Api::get_listings(listings, self)]; end
95
+
96
+ # Finds the listings of the user’s node, or that of a target node.
97
+ #
98
+ # @param options [Hash] containing:
99
+ # * guid: of the target node, optional
100
+ # *If the guid is omitted, the server will look for listings in your own node’s database.
101
+ # * pattern: [Regex] search phrase
102
+ # @return [Hash]
103
+ def query_listings(options = {})
104
+ pattern = options.delete(:pattern)
105
+ all_listings = JSON[Api::get_listings(options, self)]
106
+ listings = all_listings['listings']
107
+
108
+ if !!pattern
109
+ listings = listings.select do |l|
110
+ [l['contract_hash'], l['category'], l['title'],
111
+ l['price'].to_s, l['origin'], l['currency_code'],
112
+ l['ships_to'].join].join(' ') =~ pattern
113
+ end
114
+ end
115
+
116
+ return {'listings' => listings} if listings === all_listings
117
+
118
+ start = Time.now.to_i
119
+
120
+ @cache_timestamp = if (start - (@cache_timestamp ||= 0)) > 300
121
+ @contracts_cache = {}
122
+ start
123
+ else
124
+ @cache_timestamp
125
+ end
126
+
127
+ @contracts_cache ||= {}
128
+ (all_listings['listings'] - listings).each do |listing|
129
+ contract_hash = listing['contract_hash']
130
+ contract = @contracts_cache[contract_hash] ||= contracts(options.merge(id: listing['contract_hash']))
131
+ next unless !!contract
132
+
133
+ l = contract['vendor_offer']['listing']
134
+
135
+ if [l['metadata']['expiry'], l['item']['category'], l['item']['sku'],
136
+ l['item']['description'], l['item']['process_time'],
137
+ l['item']['keywords'].join].join(' ') =~ pattern
138
+ listings << listing && next
139
+ end
140
+ end
141
+
142
+ {'listings' => listings}
143
+ end
144
+
145
+ # Returns the followers of the user’s node, or that of a target node.
146
+ #
147
+ # @param followers [Hash] containing the guid: of the target node, optional
148
+ # * If the guid is omitted, the server will look for followers in your own node’s database.
149
+ # @return [Hash]
150
+ # @see https://gist.github.com/drwasho/742505589f62f6aa98b4#get-get_followers
151
+ def followers(followers = nil); JSON[Api::get_followers(followers, self)]; end
152
+
153
+ # Returns the following of the user’s node, or that of a target node.
154
+ #
155
+ # @param following [Hash] containing the guid: of the target node, optional
156
+ # * If the guid is omitted, the server will look for following in your own node’s database.
157
+ # @return [Hash]
158
+ # @see https://gist.github.com/drwasho/742505589f62f6aa98b4#get-get_following
159
+ def following(following = nil); JSON[Api::get_following(following, self)]; end
160
+
161
+ # Follows a target node and will cause you to receive notifications from
162
+ # that node after certain event (e.g. new listing, broadcast messages) and
163
+ # share some metadata (in future).
164
+ #
165
+ # @param follow [Hash] containing the guid: of the target node, required
166
+ # @return [Hash] containing: "success" => true or false
167
+ # @see https://gist.github.com/drwasho/bd4b28a5a07c5a952e2f#post-follow
168
+ def follow(follow); JSON[Api::post_follow(follow, self)]; end
169
+
170
+ # Stop following a target node, will cease to receive notifications and
171
+ # sharing metadata.
172
+ #
173
+ # @param unfollow [Hash] containing the guid: of the target node, required
174
+ # @return [Hash] containing: "success" => true or false
175
+ # @see https://gist.github.com/drwasho/bd4b28a5a07c5a952e2f#post-unfollow
176
+ def unfollow(unfollow); JSON[Api::post_unfollow(unfollow, self)]; end
177
+
178
+ # Add data related to the node's profile into the database, which will be
179
+ # visible to other nodes.
180
+ #
181
+ # @param profile [Hash]
182
+ # @return [Hash] containing: "success" => true or false
183
+ # @see https://gist.github.com/drwasho/bd4b28a5a07c5a952e2f#post-profile
184
+ def update_profile(profile = {}); JSON[Api::post_profile(profile, self)]; end
185
+
186
+ # Adds a social account to the user profile data of the user.
187
+ #
188
+ # @param social_account [Hash] e.g.: account_type: 'TWITTER', username: '@inertia186'
189
+ # @return [Hash] containing: "success" => true or false
190
+ # @see https://gist.github.com/drwasho/bd4b28a5a07c5a952e2f#post-social_accounts
191
+ def add_social_account(social_account = {}); JSON[Api::post_social_accounts(social_account, self)]; end
192
+
193
+ # Undocumented.
194
+ #
195
+ # @return [Hash]
196
+ def delete_social_account(social_account = {}); JSON[Api::delete_social_accounts(social_account, self)]; end
197
+
198
+ # Retrieves the listings created by either your node or a target node.
199
+ #
200
+ # @param contracts [Hash] containing the:
201
+ # * id: Unique identifier of the contract SHA256 of the JSON formatted contract (40 character hex string), required
202
+ # * guid: GUID of the node if the call is made to a target node. If omitted, the API will search for a contract ID created by your own node
203
+ # @return [Hash]
204
+ # @see https://gist.github.com/drwasho/742505589f62f6aa98b4#get-contracts
205
+ def contracts(contracts = {}); JSON[Api::get_contracts(contracts, self)]; end
206
+
207
+ # Creates a listing contract, which is saved to the database and local file
208
+ # system, as well as publish the keywords in the distributed hash table.
209
+ #
210
+ # @param contract [Hash] containing:
211
+ # * expiration_date: [UTC] Formatted string. The date the contract should expire in string formatted UTC datetime. Example:
212
+ # * "2015-11-01T00:00 UTC"
213
+ # * "" if the contract never expires
214
+ # * metadata_category: [category] Formatted string. Select from:
215
+ # * physical good
216
+ # * digital good
217
+ # * service
218
+ # * title: [title text] String. Title of the product for sale
219
+ # * description: [description text] String. Description of the item, content or service
220
+ # * currency_code: [code] Formatted string. The currency the product is priced in. may either be “btc” or a currency from this list
221
+ # * price: [value] String. The price per unit in the same currency as currency_code.
222
+ # * process_time: [time] String. The time it will take to prepare the item for shipping
223
+ # * nsfw: [true/false] Boolean. Is the item not suitable for work (i.e. 18+)
224
+ # * shipping_origin: [country/region] Formatted string. Required and only applicable if the metadata_category is a physical good
225
+ # * Where the item ships from
226
+ # * Must be a formatted string from this list
227
+ # * shipping_regions: [locations] Formatted string. Required and only applicable if the metadata_category is a physical good.
228
+ # * A list of countries/regions where the product will ship to
229
+ # * Each item in the list must be formatted from this list
230
+ # * est_delivery_domestic: [time] Estimated delivery time for domestic shipments
231
+ # * est_delivery_international: [time] String. Estimated delivery time for international shipments.
232
+ # * terms_conditions: [terms and conditions text] String. Any terms or conditions the user wishes to include.
233
+ # * returns: [returns policy text] String. Return policy.
234
+ # * shipping_currency_code: [currency code] Formatted string. The currency code used to price shipping. may either be “btc” or a currency from this list.
235
+ # * shipping_domestic: [price] String. The price of domestic shipping in the selected currency code.
236
+ # * shipping_international: [price] String. The price of nternational shipping in the selected currency code.
237
+ # * keywords: [keyword text] String. A list of string search terms for the listing. Must be fewer than 10.
238
+ # * category: [category text] Sting. A user-generated category for this product. Will show in store’s category list.
239
+ # * condition: [condition text] The condition of the product
240
+ # * sku: [sku text] String. Stock keeping unit (sku) for the listing.
241
+ # * images: [String, Array<String>] 40 character hex string. A list of SHA256 image hashes. The images should be uploaded using the upload_image api call.
242
+ # * images: '04192728d0fd8dfe6663f429a5c03a7faf907930'
243
+ # * images: ['04192728d0fd8dfe6663f429a5c03a7faf907930', '0dee4786fd02d6bc673b50309a3c831acf78ec70']
244
+ # * image_urls: [Array<String>] An array of image URLs for OBarc to first download then automatically store to this record.
245
+ # * image_urls: 'http://i.imgur.com/YHBh57j.gif'
246
+ # * image_urls: ['http://i.imgur.com/uC2KUQ6.png', 'http://i.imgur.com/RliU8Gn.jpg']
247
+ # * image_data: [Array<String>] An array of Base64 images for OBarc to automatically store to this record.
248
+ # * image_data: <String>
249
+ # * image_data: [<String>, <String>]
250
+ # * free_shipping: [boolean] "true" or "false"
251
+ # * moderators: [guids] GUID: 40 character hex string. A list of moderator GUIDs that the vendor wishes to use
252
+ # * Note: the moderator must have been previously returned by the get_moderators websocket call.
253
+ # * Given the UI workflow, this call should always be made before the contract is set.
254
+ # * options: [options text] String. A list of options for the product. Example: “size”, “color”
255
+ # * option: [option text] String.
256
+ # * For each option in the options list, another argument should be added using that option name and a list of value
257
+ # * For example, given “color” in the options list, choose from "red", "green", "purple" etc
258
+ # @return [Hash] containing: "success" => true or false, "id" => Integer
259
+ # @see https://gist.github.com/drwasho/bd4b28a5a07c5a952e2f#post-contracts
260
+ def create_contract(contract = {})
261
+ # Note, passing contract_id appears to create a clone that re-uses the
262
+ # original contract_id.
263
+
264
+ %i(image_urls image_data).each do |symbol|
265
+ upload_contract_images_with(symbol, contract) if !!contract[symbol]
266
+ end
267
+
268
+ JSON[Api::post_contract(contract, self)]
269
+ end
270
+
271
+ def upload_contract_images_with(symbol, contract = {})
272
+ contract[:images] = [contract.delete(symbol)].flatten.map do |image|
273
+ response = if image.size < 2000 && image =~ URI::ABS_URI
274
+ upload_image(image: open(image, 'rb'))
275
+ else
276
+ upload_image(image: image)
277
+ end
278
+
279
+ response['image_hashes'] if response['success']
280
+ end.flatten
281
+ end
282
+
283
+ # Undocumented.
284
+ #
285
+ # @return [Hash]
286
+ def delete_contract(contract = {}); JSON[Api::delete_contract(contract, self)]; end
287
+
288
+ # Sets your node as a Moderator, which is discoverable on the network.
289
+ #
290
+ # @return [Hash] containing: "success" => true or false
291
+ # @see https://gist.github.com/drwasho/bd4b28a5a07c5a952e2f#post-make_moderator
292
+ def make_moderator; JSON[Api::post_make_moderator(self)]; end
293
+
294
+ # Removes the node as a Moderator and is no longer discoverable on the
295
+ # network as a Moderator.
296
+ #
297
+ # @return [Hash] containing: "success" => true or false
298
+ # @see https://gist.github.com/drwasho/bd4b28a5a07c5a952e2f#post--unmake_moderator
299
+ def unmake_moderator; JSON[Api::post_unmake_moderator(self)]; end
300
+
301
+ # Purchases a contract by sending the purchase into the Vendor. The Buyer
302
+ # waits for a response to indicate whether the purchase is successful or
303
+ # not. If successful, the Buyer needs to fund the direct or multisig
304
+ # address.
305
+ #
306
+ # @param purchase_contract [Hash]
307
+ # @return [Hash] containing:
308
+ # * "success" => true or false
309
+ # * "address" => "bitcoin address to fund"
310
+ # * "amount" => "amount to fund"
311
+ # * "order_id" => "purchase order id"
312
+ # @see https://gist.github.com/drwasho/bd4b28a5a07c5a952e2f#post-purchase_contract
313
+ def purchase_contract(purchase_contract = {}); JSON[Api::post_purchase_contract(purchase_contract, self)]; end
314
+
315
+ # Sends the order confirmation and shipping information to the Buyer. If
316
+ # he’s offline, it will embed this data into the dht. The API call also
317
+ # updates the status of the order in the database.
318
+ #
319
+ # @param confirm_order [Hash]
320
+ # @return [Hash] containing: "success" => true or false
321
+ # @see https://gist.github.com/drwasho/bd4b28a5a07c5a952e2f#post-confirm_order
322
+ def confirm_order(confirm_order = {}); JSON[Api::post_confirm_order(confirm_order, self)]; end
323
+
324
+ # Saves the image in the file system and a pointer to it in the db.
325
+ #
326
+ # @param image [Hash] containing:
327
+ # * image: a list of product images to upload (LIST of images in base64. data only, no base64 prefix)
328
+ # * avatar: use this if uploading an avatar image (base64 image)
329
+ # * header: use this if uploading a header image (base64 image)
330
+ # @return [Hash] containing:
331
+ # * "success" => true or false
332
+ # * "image_hashes" => [list_of_image_hashes]
333
+ # @see https://gist.github.com/drwasho/bd4b28a5a07c5a952e2f#post-upload_image
334
+ def upload_image(image = {}); JSON[Api::post_upload_image(image.merge(cookies: cookies, base_url: base_url, verify_ssl: verify_ssl))]; end
335
+
336
+ # Sends a message with a partially signed transaction releasing funds from
337
+ # escrow to the Vendor as well as review data.
338
+ #
339
+ # @param complete_order [Hash]
340
+ # @return [Hash] containing: "success" => true or false
341
+ # @see https://gist.github.com/drwasho/bd4b28a5a07c5a952e2f#post-complete_order
342
+ def complete_order(complete_order = {}); JSON[Api::post_complete_order(complete_order, self)]; end
343
+
344
+ # Changes the settings of the node and pushes them to the database.
345
+ #
346
+ # @param settings [Hash]
347
+ # @return [Hash] containing: "success" => true or false
348
+ # @see https://gist.github.com/drwasho/bd4b28a5a07c5a952e2f#post-settings
349
+ def update_settings(settings = {}); JSON[Api::post_settings(settings, self)]; end
350
+
351
+ # Returns the settings of your node.
352
+ #
353
+ # @return [Hash]
354
+ # @see https://gist.github.com/drwasho/742505589f62f6aa98b4#get-settings
355
+ def settings; JSON[Api::get_settings(self)]; end
356
+
357
+ # Undocumented
358
+ #
359
+ # @return [Hash]
360
+ def connected_peers; JSON[Api::get_connected_peers(self)]; end
361
+
362
+ # Retreive a history of all notifications your node has received. Notifications can be sent due to:
363
+ # * A node following you
364
+ # * Events related to a purchase or sale
365
+ #
366
+ # @param FIXME not yet supported, future: limit-[number of most recent notifications]
367
+ # * Default is unlimited
368
+ # * Counts from most recent
369
+ # @return [Hash]
370
+ # @see https://gist.github.com/drwasho/742505589f62f6aa98b4#get-notifications
371
+ def notifications; JSON[Api::get_notifications(self)]; end
372
+
373
+ # Retrieves all chat message received from other nodes.
374
+ #
375
+ # @param chat_messages [Hash] containing:
376
+ # * guid [String] target node, required
377
+ # * limit [Integer] max number of chat messages to return (ignored)
378
+ # * start [FIXME] the starting point in the message list
379
+ # @return [Hash]
380
+ # @see https://gist.github.com/drwasho/742505589f62f6aa98b4#get-get_chat_messages
381
+ def chat_messages(chat_messages = {}); JSON[Api::get_chat_messages(chat_messages, self)]; end
382
+
383
+ # Retreives a list of outstandng conversations.
384
+ #
385
+ # @return [Hash]
386
+ # @see https://gist.github.com/drwasho/742505589f62f6aa98b4#get-get_chat_conversations
387
+ def chat_conversations; JSON[Api::get_chat_conversations(self)]; end
388
+
389
+ # Undocumented
390
+ #
391
+ # @return [Hash]
392
+ def delete_chat_conversation(delete_chat_conversation); JSON[Api::delete_chat_conversation(delete_chat_conversation, self)]; end
393
+
394
+ # Retrieves any sales made by the node.
395
+ #
396
+ # @return [Hash]
397
+ # @see https://gist.github.com/drwasho/742505589f62f6aa98b4#get-get_sales
398
+ def sales; JSON[Api::get_sales(self)]; end
399
+
400
+ # Retrieves any purchases made by the node.
401
+ #
402
+ # @return [Hash]
403
+ # @see https://gist.github.com/drwasho/742505589f62f6aa98b4#get-get_purchases
404
+ def purchases; JSON[Api::get_purchases(self)]; end
405
+
406
+ # Undocumented
407
+ #
408
+ # @return [Hash]
409
+ def order(order); JSON[Api::get_order(order, self)]; end
410
+
411
+ # Undocumented
412
+ #
413
+ # @return [Hash]
414
+ def cases; JSON[Api::get_cases(self)]; end
415
+
416
+ # Undocumented
417
+ #
418
+ # @return [Hash]
419
+ def order_messages(order_messages); JSON[Api::get_order_messages(order_messages, self)]; end
420
+
421
+ # Undocumented
422
+ #
423
+ # @return [Hash]
424
+ def ratings(ratings); JSON[Api::get_ratings(ratings, self)]; end
425
+
426
+ # Marks a notification as read in the database.
427
+ #
428
+ # @param notification [Hash] containing id:
429
+ # * 40 character hex string
430
+ # * Every notification has an ID that must be referenced in order to mark as read
431
+ # @return [Hash] containing: "success" => true or false
432
+ # @see https://gist.github.com/drwasho/bd4b28a5a07c5a952e2f#post-mark_notification_as_read
433
+ def mark_notification_as_read(notification = nil); JSON[Api::post_mark_notification_as_read(notification, self)]; end
434
+
435
+ # Sends some kind of "Twitter-like" message to all nodes that are following
436
+ # you. This call can take a while to complete.
437
+ #
438
+ # @return [Hash] containing:
439
+ # * "success" => true or false
440
+ # * "peers_reached" => [number reached]
441
+ # @see https://gist.github.com/drwasho/bd4b28a5a07c5a952e2f#post-broadcast
442
+ def broadcast(message = {}); JSON[Api::post_broadcast(message, self)]; end
443
+
444
+ # Undocumented
445
+ #
446
+ # @return [Hash]
447
+ def btc_price; JSON[Api::get_btc_price(self)]; end
448
+
449
+ # Undocumented
450
+ #
451
+ # @return [Hash]
452
+ def routing_table; JSON[Api::get_routing_table(self)]; end
453
+
454
+ # Marks all chat messages with a specific node as read in the database.
455
+ #
456
+ # @param chat_message_as_read [Hash] containing:
457
+ # * guid [String] GUID of the party you are chatting with
458
+ # @return [Hash] containing:
459
+ # * "success" => true or false
460
+ # @see https://gist.github.com/drwasho/bd4b28a5a07c5a952e2f#post-mark_chat_message_as_read
461
+ def mark_chat_message_as_read(mark_chat_message_as_read = nil); JSON[Api::post_mark_chat_message_as_read(mark_chat_message_as_read, self)]; end
462
+
463
+ # Sends a Twitter-like message to all nodes that are following you.
464
+ #
465
+ # @param check_for_payment [Hash] containing:
466
+ # * order_id [Integer]
467
+ # @return [Hash] containing:
468
+ # * "success" => true or false
469
+ # @see https://gist.github.com/drwasho/bd4b28a5a07c5a952e2f#post-check_for_payment
470
+ def check_for_payment(check_for_payment); JSON[Api::post_check_for_payment(check_for_payment, self)]; end
471
+
472
+ # Undocumented
473
+ #
474
+ # @param dispute_contract [Hash] containing:
475
+ # * order_id [Integer]
476
+ # @return [Hash]
477
+ def dispute_contract(dispute_contract = nil); JSON[Api::post_dispute_contract(dispute_contract, self)]; end
478
+
479
+ # Undocumented
480
+ #
481
+ # @param dispute_contract [Hash] containing:
482
+ # * order_id [Integer]
483
+ # * resolution [String]
484
+ # * buyer_percentage [Float]
485
+ # * vendor_percentage [Float]
486
+ # * moderator_percentage [Float]
487
+ # * moderator_address [String]
488
+ # @return [Hash]
489
+ def close_dispute(close_dispute = nil); JSON[Api::post_close_dispute(close_dispute, self)]; end
490
+
491
+ # Undocumented
492
+ #
493
+ # @return [Hash]
494
+ def release_funds(release_funds = nil); JSON[Api::post_release_funds(release_funds, self)]; end
495
+
496
+ # Undocumented
497
+ #
498
+ # @return [Hash]
499
+ def refund(refund = nil); JSON[Api::post_refund(refund, self)]; end
500
+
501
+ # Undocumented
502
+ #
503
+ # @return [Hash]
504
+ def mark_discussion_as_read(mark_discussion_as_read = nil); JSON[Api::post_mark_discussion_as_read(mark_discussion_as_read, self)]; end
505
+
506
+ # API call to cleanly disconnect from connected nodes and shutsdown the OpenBazaar server component.
507
+ #
508
+ # @return nil
509
+ # @see https://gist.github.com/drwasho/742505589f62f6aa98b4#get-shutdown
510
+ def shutdown!
511
+ Api::get_shutdown(self)
512
+ end
513
+ end
514
+ end