octobat 2.0.17 → 2.0.18
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/History.txt +6 -0
- data/VERSION +1 -1
- data/lib/octobat.rb +9 -1
- data/lib/octobat/file_link.rb +41 -0
- data/lib/octobat/file_upload.rb +59 -0
- data/lib/octobat/multipart_encoder.rb +131 -0
- data/lib/octobat/reporting/report_run.rb +12 -0
- data/lib/octobat/reporting/report_type.rb +12 -0
- data/lib/octobat/util.rb +5 -1
- data/lib/octobat/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 346d7f40d07e9514915f5752d92de705bd6d3875
|
4
|
+
data.tar.gz: c0e09511acf91497cbe1d3dac2e30073e5480cce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ad71a3790764557809ccc97b339d1492efd6ee5524e24bb88ee63e478a09db741ce70e9eaa1fb4918e33df6f78b06cfc51b3b446a0fe8e1b59ff9cdc55feaae
|
7
|
+
data.tar.gz: 533fde0cda76b7581715078d0d6c8eefb3a0aa9cbeaa0b35ffb209bd1370b3e87a969c62c4edbff3a27f24f3ed7d0d062d1ecf2623970ca46329fb2457a2aa60
|
data/Gemfile.lock
CHANGED
data/History.txt
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
=== 2.0.18 2020-05-25
|
2
|
+
* 3 major enhancements:
|
3
|
+
* Add support for multipart encoder (file upload)
|
4
|
+
* Add support for File API endpoints
|
5
|
+
* Add support for Reporting API endpoints
|
6
|
+
|
1
7
|
=== 2.0.17 2020-04-27
|
2
8
|
* 1 minor enhancement:
|
3
9
|
* Update Order API endpoints
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.0.
|
1
|
+
2.0.18
|
data/lib/octobat.rb
CHANGED
@@ -17,6 +17,7 @@ require 'octobat/api_operations/delete'
|
|
17
17
|
require 'octobat/api_operations/list'
|
18
18
|
|
19
19
|
# Resources
|
20
|
+
require 'octobat/multipart_encoder'
|
20
21
|
require 'octobat/util'
|
21
22
|
require 'octobat/octobat_object'
|
22
23
|
require 'octobat/api_resource'
|
@@ -51,6 +52,12 @@ require 'octobat/exports_setting'
|
|
51
52
|
require 'octobat/emails_setting'
|
52
53
|
require 'octobat/tax_id'
|
53
54
|
|
55
|
+
require 'octobat/file_upload'
|
56
|
+
require 'octobat/file_link'
|
57
|
+
require 'octobat/reporting/report_type'
|
58
|
+
require 'octobat/reporting/report_run'
|
59
|
+
|
60
|
+
|
54
61
|
# Errors
|
55
62
|
require 'octobat/errors/octobat_error'
|
56
63
|
require 'octobat/errors/octobat_lib_error'
|
@@ -63,6 +70,7 @@ module Octobat
|
|
63
70
|
#DEFAULT_CA_BUNDLE_PATH = File.dirname(__FILE__) + '/data/ca-certificates.crt'
|
64
71
|
@api_base = 'https://apiv2.octobat.com'
|
65
72
|
#@api_base = 'http://api.octobat.local:3052'
|
73
|
+
@uploads_base = "https://files.octobat.com"
|
66
74
|
|
67
75
|
@max_network_retries = 0
|
68
76
|
@max_network_retry_delay = 2
|
@@ -75,7 +83,7 @@ module Octobat
|
|
75
83
|
|
76
84
|
|
77
85
|
class << self
|
78
|
-
attr_accessor :api_key, :api_base, :verify_ssl_certs, :api_version
|
86
|
+
attr_accessor :api_key, :api_base, :verify_ssl_certs, :api_version, :uploads_base
|
79
87
|
attr_reader :max_network_retry_delay, :initial_network_retry_delay
|
80
88
|
end
|
81
89
|
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Octobat
|
2
|
+
class FileLink < APIResource
|
3
|
+
include Octobat::APIOperations::Create
|
4
|
+
extend Octobat::APIOperations::List
|
5
|
+
|
6
|
+
def self.create(params = {}, opts = {})
|
7
|
+
api_key, headers = Util.parse_opts(opts)
|
8
|
+
response, api_key = Octobat.request(:post, self.url, api_key, params, headers, Octobat.uploads_base)
|
9
|
+
Util.convert_to_octobat_object(response, api_key)
|
10
|
+
end
|
11
|
+
|
12
|
+
def refresh
|
13
|
+
response, api_key = Octobat.request(:get, url, @api_key, @retrieve_options, @headers, Octobat.uploads_base)
|
14
|
+
refresh_from(response, api_key)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.list(filters={}, opts={})
|
18
|
+
set_parent_resource(filters)
|
19
|
+
api_key, headers = Util.parse_opts(opts)
|
20
|
+
|
21
|
+
api_key ||= @api_key
|
22
|
+
|
23
|
+
f = filters.select{|request_filter| !@parent_resource.has_key?(request_filter)}
|
24
|
+
|
25
|
+
response, api_key = Octobat.request(:get, url, api_key, f, headers, Octobat.uploads_base)
|
26
|
+
obj = ListObject.construct_from(response, api_key)
|
27
|
+
|
28
|
+
obj.filters = filters.dup
|
29
|
+
obj.cursors[:ending_before] = obj.filters.delete(:ending_before)
|
30
|
+
obj.cursors[:starting_after] = obj.filters.delete(:starting_after)
|
31
|
+
|
32
|
+
obj.filters.delete(:expand)
|
33
|
+
obj.parent_resource = @parent_resource
|
34
|
+
|
35
|
+
obj
|
36
|
+
end
|
37
|
+
|
38
|
+
self.singleton_class.send(:alias_method, :all, :list)
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Octobat
|
2
|
+
class FileUpload < APIResource
|
3
|
+
include Octobat::APIOperations::Create
|
4
|
+
extend Octobat::APIOperations::List
|
5
|
+
|
6
|
+
def self.url
|
7
|
+
"/files"
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
def self.create(params = {}, opts = {})
|
12
|
+
if params[:attachment] && !params[:attachment].is_a?(String)
|
13
|
+
unless params[:attachment].respond_to?(:read)
|
14
|
+
raise ArgumentError, "attachment must respond to `#read`"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
api_key, headers = Util.parse_opts(opts)
|
19
|
+
headers = headers.merge(content_type: MultipartEncoder::MULTIPART_FORM_DATA)
|
20
|
+
|
21
|
+
response, api_key = Octobat.request(:post, self.url, api_key, params, headers, Octobat.uploads_base)
|
22
|
+
Util.convert_to_octobat_object(response, api_key)
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
def refresh
|
27
|
+
response, api_key = Octobat.request(:get, url, @api_key, @retrieve_options, @headers, Octobat.uploads_base)
|
28
|
+
refresh_from(response, api_key)
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def self.list(filters={}, opts={})
|
33
|
+
set_parent_resource(filters)
|
34
|
+
api_key, headers = Util.parse_opts(opts)
|
35
|
+
|
36
|
+
api_key ||= @api_key
|
37
|
+
|
38
|
+
f = filters.select{|request_filter| !@parent_resource.has_key?(request_filter)}
|
39
|
+
|
40
|
+
response, api_key = Octobat.request(:get, url, api_key, f, headers, Octobat.uploads_base)
|
41
|
+
obj = ListObject.construct_from(response, api_key)
|
42
|
+
|
43
|
+
obj.filters = filters.dup
|
44
|
+
obj.cursors[:ending_before] = obj.filters.delete(:ending_before)
|
45
|
+
obj.cursors[:starting_after] = obj.filters.delete(:starting_after)
|
46
|
+
|
47
|
+
obj.filters.delete(:expand)
|
48
|
+
obj.parent_resource = @parent_resource
|
49
|
+
|
50
|
+
obj
|
51
|
+
end
|
52
|
+
|
53
|
+
self.singleton_class.send(:alias_method, :all, :list)
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "securerandom"
|
4
|
+
require "tempfile"
|
5
|
+
|
6
|
+
module Octobat
|
7
|
+
# Encodes parameters into a `multipart/form-data` payload as described by RFC
|
8
|
+
# 2388:
|
9
|
+
#
|
10
|
+
# https://tools.ietf.org/html/rfc2388
|
11
|
+
#
|
12
|
+
# This is most useful for transferring file-like objects.
|
13
|
+
#
|
14
|
+
# Parameters should be added with `#encode`. When ready, use `#body` to get
|
15
|
+
# the encoded result and `#content_type` to get the value that should be
|
16
|
+
# placed in the `Content-Type` header of a subsequent request (which includes
|
17
|
+
# a boundary value).
|
18
|
+
class MultipartEncoder
|
19
|
+
MULTIPART_FORM_DATA = "multipart/form-data"
|
20
|
+
|
21
|
+
# A shortcut for encoding a single set of parameters and finalizing a
|
22
|
+
# result.
|
23
|
+
#
|
24
|
+
# Returns an encoded body and the value that should be set in the content
|
25
|
+
# type header of a subsequent request.
|
26
|
+
def self.encode(params)
|
27
|
+
encoder = MultipartEncoder.new
|
28
|
+
encoder.encode(params)
|
29
|
+
encoder.close
|
30
|
+
[encoder.body, encoder.content_type]
|
31
|
+
end
|
32
|
+
|
33
|
+
# Gets the object's randomly generated boundary string.
|
34
|
+
attr_reader :boundary
|
35
|
+
|
36
|
+
# Initializes a new multipart encoder.
|
37
|
+
def initialize
|
38
|
+
# Kind of weird, but required by Rubocop because the unary plus operator
|
39
|
+
# is considered faster than `Octobat.new`.
|
40
|
+
@body = +""
|
41
|
+
|
42
|
+
# Chose the same number of random bytes that Go uses in its standard
|
43
|
+
# library implementation. Easily enough entropy to ensure that it won't
|
44
|
+
# be present in a file we're sending.
|
45
|
+
@boundary = SecureRandom.hex(30)
|
46
|
+
|
47
|
+
@closed = false
|
48
|
+
@first_field = true
|
49
|
+
end
|
50
|
+
|
51
|
+
# Gets the encoded body. `#close` must be called first.
|
52
|
+
def body
|
53
|
+
raise "object must be closed before getting body" unless @closed
|
54
|
+
|
55
|
+
@body
|
56
|
+
end
|
57
|
+
|
58
|
+
# Finalizes the object by writing the final boundary.
|
59
|
+
def close
|
60
|
+
raise "object already closed" if @closed
|
61
|
+
|
62
|
+
@body << "\r\n"
|
63
|
+
@body << "--#{@boundary}--"
|
64
|
+
|
65
|
+
@closed = true
|
66
|
+
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
|
70
|
+
# Gets the value including boundary that should be put into a multipart
|
71
|
+
# request's `Content-Type`.
|
72
|
+
def content_type
|
73
|
+
"#{MULTIPART_FORM_DATA}; boundary=#{@boundary}"
|
74
|
+
end
|
75
|
+
|
76
|
+
# Encodes a set of parameters to the body.
|
77
|
+
#
|
78
|
+
# Note that parameters are expected to be a hash, but a "flat" hash such
|
79
|
+
# that complex substructures like hashes and arrays have already been
|
80
|
+
# appropriately Octobat-encoded. Pass a complex structure through
|
81
|
+
# `Util.flatten_params` first before handing it off to this method.
|
82
|
+
def encode(params)
|
83
|
+
raise "no more parameters can be written to closed object" if @closed
|
84
|
+
|
85
|
+
params.each do |name, val|
|
86
|
+
if val.is_a?(::File) || val.is_a?(::Tempfile)
|
87
|
+
write_field(name, val.read, filename: ::File.basename(val.path))
|
88
|
+
elsif val.respond_to?(:read)
|
89
|
+
write_field(name, val.read, filename: "blob")
|
90
|
+
else
|
91
|
+
write_field(name, val, filename: nil)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
nil
|
96
|
+
end
|
97
|
+
|
98
|
+
#
|
99
|
+
# private
|
100
|
+
#
|
101
|
+
|
102
|
+
# Escapes double quotes so that the given value can be used in a
|
103
|
+
# double-quoted string and replaces any linebreak characters with spaces.
|
104
|
+
private def escape(str)
|
105
|
+
str.gsub('"', "%22").tr("\n", " ").tr("\r", " ")
|
106
|
+
end
|
107
|
+
|
108
|
+
private def write_field(name, data, filename:)
|
109
|
+
if !@first_field
|
110
|
+
@body << "\r\n"
|
111
|
+
else
|
112
|
+
@first_field = false
|
113
|
+
end
|
114
|
+
|
115
|
+
@body << "--#{@boundary}\r\n"
|
116
|
+
|
117
|
+
if filename
|
118
|
+
@body << %(Content-Disposition: form-data) +
|
119
|
+
%(; name="#{escape(name.to_s)}") +
|
120
|
+
%(; filename="#{escape(filename)}"\r\n)
|
121
|
+
@body << %(Content-Type: application/octet-stream\r\n)
|
122
|
+
else
|
123
|
+
@body << %(Content-Disposition: form-data) +
|
124
|
+
%(; name="#{escape(name.to_s)}"\r\n)
|
125
|
+
end
|
126
|
+
|
127
|
+
@body << "\r\n"
|
128
|
+
@body << data.to_s
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
data/lib/octobat/util.rb
CHANGED
@@ -65,7 +65,11 @@ module Octobat
|
|
65
65
|
'document_email_template' => DocumentEmailTemplate,
|
66
66
|
'exports_setting' => ExportsSetting,
|
67
67
|
'document' => Document,
|
68
|
-
'emails_setting' => EmailsSetting
|
68
|
+
'emails_setting' => EmailsSetting,
|
69
|
+
'file' => FileUpload,
|
70
|
+
'file_link' => FileLink,
|
71
|
+
'reporting.report_type' => Reporting::ReportType,
|
72
|
+
'reporting.report_run' => Reporting::ReportRun
|
69
73
|
}
|
70
74
|
end
|
71
75
|
|
data/lib/octobat/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: octobat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.18
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gaultier Laperche
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-05-
|
11
|
+
date: 2020-05-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rest-client
|
@@ -79,10 +79,13 @@ files:
|
|
79
79
|
- lib/octobat/errors/octobat_error.rb
|
80
80
|
- lib/octobat/errors/octobat_lib_error.rb
|
81
81
|
- lib/octobat/exports_setting.rb
|
82
|
+
- lib/octobat/file_link.rb
|
83
|
+
- lib/octobat/file_upload.rb
|
82
84
|
- lib/octobat/invoice.rb
|
83
85
|
- lib/octobat/invoice_numbering_sequence.rb
|
84
86
|
- lib/octobat/item.rb
|
85
87
|
- lib/octobat/list_object.rb
|
88
|
+
- lib/octobat/multipart_encoder.rb
|
86
89
|
- lib/octobat/octobat_object.rb
|
87
90
|
- lib/octobat/order.rb
|
88
91
|
- lib/octobat/payment_recipient.rb
|
@@ -91,6 +94,8 @@ files:
|
|
91
94
|
- lib/octobat/payout.rb
|
92
95
|
- lib/octobat/product.rb
|
93
96
|
- lib/octobat/proforma_invoice.rb
|
97
|
+
- lib/octobat/reporting/report_run.rb
|
98
|
+
- lib/octobat/reporting/report_type.rb
|
94
99
|
- lib/octobat/singleton_api_resource.rb
|
95
100
|
- lib/octobat/tax_evidence.rb
|
96
101
|
- lib/octobat/tax_evidence_request.rb
|