noko 0.0.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +22 -0
- data/README.md +40 -0
- data/lib/noko.rb +11 -0
- data/lib/noko/client.rb +83 -0
- data/lib/noko/client/account.rb +7 -0
- data/lib/noko/client/current_user.rb +19 -0
- data/lib/noko/client/entries.rb +23 -0
- data/lib/noko/client/expenses.rb +23 -0
- data/lib/noko/client/invoices.rb +39 -0
- data/lib/noko/client/project_groups.rb +31 -0
- data/lib/noko/client/projects.rb +55 -0
- data/lib/noko/client/tags.rb +35 -0
- data/lib/noko/client/timers.rb +31 -0
- data/lib/noko/client/users.rb +39 -0
- data/lib/noko/errors.rb +5 -0
- data/lib/noko/link_header.rb +16 -0
- data/lib/noko/params.rb +27 -0
- data/lib/noko/record.rb +31 -0
- data/lib/noko/version.rb +3 -0
- data/noko.gemspec +17 -0
- data/test/noko/client/account_test.rb +9 -0
- data/test/noko/client/current_user_test.rb +39 -0
- data/test/noko/client/entries_test.rb +45 -0
- data/test/noko/client/errors_test.rb +27 -0
- data/test/noko/client/expenses_test.rb +45 -0
- data/test/noko/client/invoices_test.rb +75 -0
- data/test/noko/client/options_test.rb +27 -0
- data/test/noko/client/project_groups_test.rb +63 -0
- data/test/noko/client/projects_test.rb +99 -0
- data/test/noko/client/response_test.rb +39 -0
- data/test/noko/client/tags_test.rb +63 -0
- data/test/noko/client/timers_test.rb +57 -0
- data/test/noko/client/users_test.rb +75 -0
- data/test/noko/client_test.rb +59 -0
- data/test/noko/record_test.rb +28 -0
- metadata +85 -8
@@ -0,0 +1,39 @@
|
|
1
|
+
module Noko
|
2
|
+
class Client
|
3
|
+
def get_users(params = nil)
|
4
|
+
get('/v2/users', params)
|
5
|
+
end
|
6
|
+
|
7
|
+
def get_user(id)
|
8
|
+
get("/v2/users/#{id}")
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_user_entries(id, params = nil)
|
12
|
+
get("/v2/users/#{id}/entries", params)
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_user_expenses(id, params = nil)
|
16
|
+
get("/v2/users/#{id}/expenses", params)
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_user(attributes)
|
20
|
+
post('/v2/users', attributes)
|
21
|
+
end
|
22
|
+
|
23
|
+
def update_user(id, attributes)
|
24
|
+
put("/v2/users/#{id}", attributes)
|
25
|
+
end
|
26
|
+
|
27
|
+
def delete_user(id)
|
28
|
+
delete("/v2/users/#{id}")
|
29
|
+
end
|
30
|
+
|
31
|
+
def reactivate_user(id)
|
32
|
+
put("/v2/users/#{id}/activate")
|
33
|
+
end
|
34
|
+
|
35
|
+
def deactivate_user(id)
|
36
|
+
put("/v2/users/#{id}/deactivate")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/noko/errors.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'noko/record'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module Noko
|
5
|
+
module LinkHeader # :nodoc:
|
6
|
+
extend self
|
7
|
+
|
8
|
+
REGEXP = /<([^>]+)>; rel="(\w+)"/
|
9
|
+
|
10
|
+
def parse(string)
|
11
|
+
string.scan(REGEXP).each_with_object(Record.new) do |(uri, rel), record|
|
12
|
+
record[rel.to_sym] = URI.parse(uri).request_uri
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/noko/params.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module Noko
|
4
|
+
module Params # :nodoc:
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def join(path, params = nil)
|
8
|
+
return path if params.nil? || params.empty?
|
9
|
+
|
10
|
+
path + '?' + encode(params)
|
11
|
+
end
|
12
|
+
|
13
|
+
def encode(params)
|
14
|
+
params.map { |k, v| "#{escape(k)}=#{array_escape(v)}" }.join('&')
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def array_escape(object)
|
20
|
+
Array(object).map { |value| escape(value) }.join(',')
|
21
|
+
end
|
22
|
+
|
23
|
+
def escape(component)
|
24
|
+
CGI.escape(component.to_s)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/noko/record.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Noko
|
2
|
+
class Record
|
3
|
+
def initialize(attributes = {})
|
4
|
+
@attributes = attributes
|
5
|
+
end
|
6
|
+
|
7
|
+
def [](name)
|
8
|
+
@attributes[name]
|
9
|
+
end
|
10
|
+
|
11
|
+
def []=(name, value)
|
12
|
+
@attributes[name] = value
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_missing(name, *args, &block)
|
16
|
+
if @attributes.has_key?(name) && args.empty? && block.nil?
|
17
|
+
return @attributes[name]
|
18
|
+
else
|
19
|
+
super name, *args, &block
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def respond_to_missing?(name, include_private = false)
|
24
|
+
@attributes.has_key?(name)
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_h
|
28
|
+
@attributes
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/noko/version.rb
ADDED
data/noko.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'noko'
|
3
|
+
s.version = '1.4.0'
|
4
|
+
s.license = 'MIT'
|
5
|
+
s.platform = Gem::Platform::RUBY
|
6
|
+
s.authors = ['Tim Craft']
|
7
|
+
s.email = ['mail@timcraft.com']
|
8
|
+
s.homepage = 'https://github.com/timcraft/noko'
|
9
|
+
s.description = 'Ruby client for Version 2 of the Noko/Freckle API'
|
10
|
+
s.summary = 'Ruby client for Version 2 of the Noko/Freckle API'
|
11
|
+
s.files = Dir.glob('{lib,test}/**/*') + %w(LICENSE.txt README.md noko.gemspec)
|
12
|
+
s.required_ruby_version = '>= 1.9.3'
|
13
|
+
s.add_development_dependency('rake', '~> 12')
|
14
|
+
s.add_development_dependency('webmock', '~> 3.0')
|
15
|
+
s.add_development_dependency('minitest', '~> 5.0')
|
16
|
+
s.require_path = 'lib'
|
17
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative '../client_test'
|
2
|
+
|
3
|
+
class ClientCurrentUserTest < ClientTest
|
4
|
+
def test_get_current_user
|
5
|
+
expect_request(:get, "#{base_url}/current_user").with(auth_header).to_return(json_response)
|
6
|
+
|
7
|
+
assert_instance_of Noko::Record, client.get_current_user
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_get_current_user_entries
|
11
|
+
expect_request(:get, "#{base_url}/current_user/entries").with(auth_header).to_return(json_array_response)
|
12
|
+
|
13
|
+
assert_equal [], client.get_current_user_entries
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_get_current_user_entries_encodes_params
|
17
|
+
expect_request(:get, "#{base_url}/current_user/entries?billable=true")
|
18
|
+
|
19
|
+
client.get_current_user_entries(billable: true)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_get_current_user_expenses
|
23
|
+
expect_request(:get, "#{base_url}/current_user/expenses").with(auth_header).to_return(json_array_response)
|
24
|
+
|
25
|
+
assert_equal [], client.get_current_user_expenses
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_get_current_user_expenses_encodes_params
|
29
|
+
expect_request(:get, "#{base_url}/current_user/expenses?invoiced=true")
|
30
|
+
|
31
|
+
client.get_current_user_expenses(invoiced: true)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_update_current_user
|
35
|
+
expect_request(:put, "#{base_url}/current_user").with(json_request).to_return(json_response)
|
36
|
+
|
37
|
+
assert_instance_of Noko::Record, client.update_current_user(week_start: 'monday')
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative '../client_test'
|
2
|
+
|
3
|
+
class ClientEntriesTest < ClientTest
|
4
|
+
def test_get_entries
|
5
|
+
expect_request(:get, "#{base_url}/entries").with(auth_header).to_return(json_array_response)
|
6
|
+
|
7
|
+
assert_equal [], client.get_entries
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_get_entries_encodes_params
|
11
|
+
expect_request(:get, "#{base_url}/entries?billable=true")
|
12
|
+
|
13
|
+
client.get_entries(billable: true)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_get_entries_encodes_project_ids
|
17
|
+
expect_request(:get, "#{base_url}/entries?project_ids=123,456,789")
|
18
|
+
|
19
|
+
client.get_entries(project_ids: ids)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_get_entry
|
23
|
+
expect_request(:get, "#{base_url}/entries/#{id}").with(auth_header).to_return(json_response)
|
24
|
+
|
25
|
+
assert_instance_of Noko::Record, client.get_entry(id)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_create_entry
|
29
|
+
expect_request(:post, "#{base_url}/entries").with(json_request).to_return(json_response.merge(status: 201))
|
30
|
+
|
31
|
+
assert_instance_of Noko::Record, client.create_entry(date: Date.today, minutes: 60)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_update_entry
|
35
|
+
expect_request(:put, "#{base_url}/entries/#{id}").with(json_request).to_return(json_response)
|
36
|
+
|
37
|
+
assert_instance_of Noko::Record, client.update_entry(id, minutes: 120)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_delete_entry
|
41
|
+
expect_request(:delete, "#{base_url}/entries/#{id}").with(auth_header).to_return(status: 204)
|
42
|
+
|
43
|
+
assert_equal :no_content, client.delete_entry(id)
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative '../client_test'
|
2
|
+
|
3
|
+
class ClientErrorsTest < ClientTest
|
4
|
+
def test_bad_request_errors
|
5
|
+
message = 'The Project cannot be deleted because it has entries, expenses, or invoices.'
|
6
|
+
|
7
|
+
response = json_response.merge(status: 400, body: %({"message":"#{message}"}))
|
8
|
+
|
9
|
+
stub_request(:delete, "#{base_url}/projects/#{id}").to_return(response)
|
10
|
+
|
11
|
+
exception = assert_raises(Noko::Error) do
|
12
|
+
client.delete_project(id)
|
13
|
+
end
|
14
|
+
|
15
|
+
assert_includes exception.message, message
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_authentication_errors
|
19
|
+
response = json_response.merge(status: 401)
|
20
|
+
|
21
|
+
stub_request(:get, "#{base_url}/entries").to_return(response)
|
22
|
+
|
23
|
+
assert_raises(Noko::AuthenticationError) do
|
24
|
+
client.get_entries
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative '../client_test'
|
2
|
+
|
3
|
+
class ClientExpensesTest < ClientTest
|
4
|
+
def test_get_expenses
|
5
|
+
expect_request(:get, "#{base_url}/expenses").with(auth_header).to_return(json_array_response)
|
6
|
+
|
7
|
+
assert_equal [], client.get_expenses
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_get_expenses_encodes_params
|
11
|
+
expect_request(:get, "#{base_url}/expenses?invoiced=true")
|
12
|
+
|
13
|
+
client.get_expenses(invoiced: true)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_get_expenses_encodes_ids
|
17
|
+
expect_request(:get, "#{base_url}/expenses?project_ids=123,456,789")
|
18
|
+
|
19
|
+
client.get_expenses(project_ids: ids)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_get_expense
|
23
|
+
expect_request(:get, "#{base_url}/expenses/#{id}").with(auth_header).to_return(json_response)
|
24
|
+
|
25
|
+
assert_instance_of Noko::Record, client.get_expense(id)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_create_expense
|
29
|
+
expect_request(:post, "#{base_url}/expenses").with(json_request).to_return(json_response.merge(status: 201))
|
30
|
+
|
31
|
+
assert_instance_of Noko::Record, client.create_expense(date: Date.today, project_id: id, price: '14.55')
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_update_expense
|
35
|
+
expect_request(:put, "#{base_url}/expenses/#{id}").with(json_request).to_return(json_response)
|
36
|
+
|
37
|
+
assert_instance_of Noko::Record, client.update_expense(id, price: '19.99')
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_delete_expense
|
41
|
+
expect_request(:delete, "#{base_url}/expenses/#{id}").with(auth_header).to_return(status: 204)
|
42
|
+
|
43
|
+
assert_equal :no_content, client.delete_expense(id)
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require_relative '../client_test'
|
2
|
+
|
3
|
+
class ClientInvoicesTest < ClientTest
|
4
|
+
def test_get_invoices
|
5
|
+
expect_request(:get, "#{base_url}/invoices").with(auth_header).to_return(json_array_response)
|
6
|
+
|
7
|
+
assert_equal [], client.get_invoices
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_get_invoices_encodes_params
|
11
|
+
expect_request(:get, "#{base_url}/invoices?state=unpaid")
|
12
|
+
|
13
|
+
client.get_invoices(state: :unpaid)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_get_invoice
|
17
|
+
expect_request(:get, "#{base_url}/invoices/#{id}").with(auth_header).to_return(json_response)
|
18
|
+
|
19
|
+
assert_instance_of Noko::Record, client.get_invoice(id)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_create_invoice
|
23
|
+
expect_request(:post, "#{base_url}/invoices").with(json_request).to_return(json_response.merge(status: 201))
|
24
|
+
|
25
|
+
assert_instance_of Noko::Record, client.create_invoice(invoice_date: Date.today)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_update_invoice
|
29
|
+
expect_request(:put, "#{base_url}/invoices/#{id}").with(json_request).to_return(json_response)
|
30
|
+
|
31
|
+
assert_instance_of Noko::Record, client.update_invoice(id, reference: 'AB 0001')
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_mark_invoice_paid
|
35
|
+
expect_request(:put, "#{base_url}/invoices/#{id}/paid").with(auth_header).to_return(status: 204)
|
36
|
+
|
37
|
+
assert_equal :no_content, client.mark_invoice_paid(id)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_mark_invoice_unpaid
|
41
|
+
expect_request(:put, "#{base_url}/invoices/#{id}/unpaid").with(auth_header).to_return(status: 204)
|
42
|
+
|
43
|
+
assert_equal :no_content, client.mark_invoice_unpaid(id)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_get_invoice_entries
|
47
|
+
expect_request(:get, "#{base_url}/invoices/#{id}/entries").with(auth_header).to_return(json_array_response)
|
48
|
+
|
49
|
+
assert_equal [], client.get_invoice_entries(id)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_get_invoice_entries_encodes_params
|
53
|
+
expect_request(:get, "#{base_url}/invoices/#{id}/entries?billable=true")
|
54
|
+
|
55
|
+
client.get_invoice_entries(id, billable: true)
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_get_invoice_expenses
|
59
|
+
expect_request(:get, "#{base_url}/invoices/#{id}/expenses").with(auth_header).to_return(json_array_response)
|
60
|
+
|
61
|
+
assert_equal [], client.get_invoice_expenses(id)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_get_invoice_expenses_encodes_params
|
65
|
+
expect_request(:get, "#{base_url}/invoices/#{id}/expenses?invoiced=false")
|
66
|
+
|
67
|
+
client.get_invoice_expenses(id, invoiced: false)
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_delete_invoice
|
71
|
+
expect_request(:delete, "#{base_url}/invoices/#{id}").with(auth_header).to_return(status: 204)
|
72
|
+
|
73
|
+
assert_equal :no_content, client.delete_invoice(id)
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative '../client_test'
|
2
|
+
|
3
|
+
class ClientOptionsTest < ClientTest
|
4
|
+
def user_agent
|
5
|
+
'account.nokotime.com'
|
6
|
+
end
|
7
|
+
|
8
|
+
def access_token
|
9
|
+
'oauth2-access-token'
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_user_agent_option
|
13
|
+
client = Noko::Client.new(token: token, user_agent: user_agent)
|
14
|
+
|
15
|
+
expect_request(:get, "#{base_url}/entries").with(headers: {'User-Agent' => user_agent})
|
16
|
+
|
17
|
+
client.get_entries
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_access_token_option
|
21
|
+
client = Noko::Client.new(access_token: access_token)
|
22
|
+
|
23
|
+
expect_request(:get, "#{base_url}/entries").with(headers: {'Authorization' => 'token oauth2-access-token'})
|
24
|
+
|
25
|
+
client.get_entries
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require_relative '../client_test'
|
2
|
+
|
3
|
+
class ClientProjectGroupsTest < ClientTest
|
4
|
+
def test_get_project_groups
|
5
|
+
expect_request(:get, "#{base_url}/project_groups").with(auth_header).to_return(json_array_response)
|
6
|
+
|
7
|
+
assert_equal [], client.get_project_groups
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_get_project_groups_encodes_params
|
11
|
+
expect_request(:get, "#{base_url}/project_groups?name=Sprockets")
|
12
|
+
|
13
|
+
client.get_project_groups(name: 'Sprockets')
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_get_project_group
|
17
|
+
expect_request(:get, "#{base_url}/project_groups/#{id}").with(auth_header).to_return(json_response)
|
18
|
+
|
19
|
+
assert_instance_of Noko::Record, client.get_project_group(id)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_create_project_group
|
23
|
+
expect_request(:post, "#{base_url}/project_groups").with(json_request).to_return(json_response.merge(status: 201))
|
24
|
+
|
25
|
+
assert_instance_of Noko::Record, client.create_project_group(name: 'Sprockets, Inc.')
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_get_project_group_entries
|
29
|
+
expect_request(:get, "#{base_url}/project_groups/#{id}/entries").with(auth_header).to_return(json_array_response)
|
30
|
+
|
31
|
+
assert_equal [], client.get_project_group_entries(id)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_get_project_group_entries_encodes_params
|
35
|
+
expect_request(:get, "#{base_url}/project_groups/#{id}/entries?billable=true")
|
36
|
+
|
37
|
+
client.get_project_group_entries(id, billable: true)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_get_project_group_projects
|
41
|
+
expect_request(:get, "#{base_url}/project_groups/#{id}/projects").with(auth_header).to_return(json_array_response)
|
42
|
+
|
43
|
+
assert_equal [], client.get_project_group_projects(id)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_get_project_group_projects_encodes_params
|
47
|
+
expect_request(:get, "#{base_url}/project_groups/#{id}/projects?billable=true")
|
48
|
+
|
49
|
+
client.get_project_group_projects(id, billable: true)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_update_project_group
|
53
|
+
expect_request(:put, "#{base_url}/project_groups/#{id}").with(json_request).to_return(json_response)
|
54
|
+
|
55
|
+
assert_instance_of Noko::Record, client.update_project_group(id, name: 'Sprockets, Inc.')
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_delete_project_group
|
59
|
+
expect_request(:delete, "#{base_url}/project_groups/#{id}").with(auth_header).to_return(status: 204)
|
60
|
+
|
61
|
+
assert_equal :no_content, client.delete_project_group(id)
|
62
|
+
end
|
63
|
+
end
|