togglv8-tfl 0.0.1
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 +7 -0
- data/.codeclimate.yml +16 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +4 -0
- data/.rdoc_options +23 -0
- data/.rspec +1 -0
- data/.rubocop.yml +1156 -0
- data/.travis.yml +11 -0
- data/CHANGELOG.md +101 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +160 -0
- data/Rakefile +6 -0
- data/lib/logging.rb +38 -0
- data/lib/reportsv2.rb +187 -0
- data/lib/togglv8.rb +13 -0
- data/lib/togglv8/clients.rb +37 -0
- data/lib/togglv8/connection.rb +99 -0
- data/lib/togglv8/dashboard.rb +14 -0
- data/lib/togglv8/project_users.rb +32 -0
- data/lib/togglv8/projects.rb +112 -0
- data/lib/togglv8/tags.rb +25 -0
- data/lib/togglv8/tasks.rb +55 -0
- data/lib/togglv8/time_entries.rb +93 -0
- data/lib/togglv8/togglv8.rb +55 -0
- data/lib/togglv8/users.rb +74 -0
- data/lib/togglv8/version.rb +4 -0
- data/lib/togglv8/workspaces.rb +47 -0
- data/spec/lib/reportsv2_spec.rb +254 -0
- data/spec/lib/togglv8/clients_spec.rb +145 -0
- data/spec/lib/togglv8/dashboard_spec.rb +31 -0
- data/spec/lib/togglv8/projects_spec.rb +111 -0
- data/spec/lib/togglv8/tags_spec.rb +54 -0
- data/spec/lib/togglv8/tasks_spec.rb +100 -0
- data/spec/lib/togglv8/time_entries_spec.rb +425 -0
- data/spec/lib/togglv8/users_spec.rb +82 -0
- data/spec/lib/togglv8/workspaces_spec.rb +40 -0
- data/spec/lib/togglv8_spec.rb +77 -0
- data/spec/spec_helper.rb +85 -0
- data/spec/togglv8_spec_helper.rb +75 -0
- data/togglv8.gemspec +34 -0
- metadata +251 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative 'clients'
|
2
|
+
require_relative 'dashboard'
|
3
|
+
require_relative 'project_users'
|
4
|
+
require_relative 'projects'
|
5
|
+
require_relative 'tags'
|
6
|
+
require_relative 'tasks'
|
7
|
+
require_relative 'time_entries'
|
8
|
+
require_relative 'users'
|
9
|
+
require_relative 'version'
|
10
|
+
require_relative 'workspaces'
|
11
|
+
|
12
|
+
module TogglV8
|
13
|
+
TOGGL_API_URL = 'https://www.toggl.com/api/'
|
14
|
+
|
15
|
+
class API
|
16
|
+
include TogglV8::Connection
|
17
|
+
|
18
|
+
TOGGL_API_V8_URL = TOGGL_API_URL + 'v8/'
|
19
|
+
|
20
|
+
attr_reader :conn
|
21
|
+
|
22
|
+
def initialize(username=nil, password=API_TOKEN, opts={})
|
23
|
+
debug(false)
|
24
|
+
if username.nil? && password == API_TOKEN
|
25
|
+
toggl_api_file = File.join(Dir.home, TOGGL_FILE)
|
26
|
+
# logger.debug("toggl_api_file = #{toggl_api_file}")
|
27
|
+
if File.exist?(toggl_api_file) then
|
28
|
+
username = IO.read(toggl_api_file)
|
29
|
+
else
|
30
|
+
raise "Expecting one of:\n" +
|
31
|
+
" 1) api_token in file #{toggl_api_file}, or\n" +
|
32
|
+
" 2) parameter: (api_token), or\n" +
|
33
|
+
" 3) parameters: (username, password).\n" +
|
34
|
+
"\n\tSee https://github.com/kanet77/togglv8#togglv8api" +
|
35
|
+
"\n\tand https://github.com/toggl/toggl_api_docs/blob/master/chapters/authentication.md"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
@conn = TogglV8::Connection.open(username, password,
|
40
|
+
TOGGL_API_V8_URL, opts)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module TogglV8
|
2
|
+
class API
|
3
|
+
|
4
|
+
##
|
5
|
+
# ---------
|
6
|
+
# :section: Users
|
7
|
+
#
|
8
|
+
# api_token : (string)
|
9
|
+
# default_wid : default workspace id (integer)
|
10
|
+
# email : (string)
|
11
|
+
# jquery_timeofday_format : (string)
|
12
|
+
# jquery_date_format : (string)
|
13
|
+
# timeofday_format : (string)
|
14
|
+
# date_format : (string)
|
15
|
+
# store_start_and_stop_time : whether start and stop time are saved on time entry (boolean)
|
16
|
+
# beginning_of_week : (integer, Sunday=0)
|
17
|
+
# language : user's language (string)
|
18
|
+
# image_url : url with the user's profile picture(string)
|
19
|
+
# sidebar_piechart : should a piechart be shown on the sidebar (boolean)
|
20
|
+
# at : timestamp of last changes
|
21
|
+
# new_blog_post : an object with toggl blog post title and link
|
22
|
+
|
23
|
+
def me(all=nil)
|
24
|
+
# NOTE: response['since'] is discarded because it is outside response['data']
|
25
|
+
# (See TogglV8::API#get in lib/togglv8.rb)
|
26
|
+
get "me%s" % [all.nil? ? "" : "?with_related_data=#{all}"]
|
27
|
+
end
|
28
|
+
|
29
|
+
def my_clients(user=nil)
|
30
|
+
user = me(all=true) if user.nil?
|
31
|
+
user['clients'] || {}
|
32
|
+
end
|
33
|
+
|
34
|
+
def my_projects(user=nil)
|
35
|
+
user = me(all=true) if user.nil?
|
36
|
+
return {} unless user['projects']
|
37
|
+
projects = user['projects']
|
38
|
+
projects.delete_if { |p| p['server_deleted_at'] }
|
39
|
+
end
|
40
|
+
|
41
|
+
def my_deleted_projects(user=nil)
|
42
|
+
user = me(all=true) if user.nil?
|
43
|
+
return {} unless user['projects']
|
44
|
+
projects = user['projects']
|
45
|
+
projects.keep_if { |p| p['server_deleted_at'] }
|
46
|
+
end
|
47
|
+
|
48
|
+
def my_tags(user=nil)
|
49
|
+
user = me(all=true) if user.nil?
|
50
|
+
user['tags'] || {}
|
51
|
+
end
|
52
|
+
|
53
|
+
def my_tasks(user=nil)
|
54
|
+
user = me(all=true) if user.nil?
|
55
|
+
user['tasks'] || {}
|
56
|
+
end
|
57
|
+
|
58
|
+
def my_time_entries(user=nil)
|
59
|
+
user = me(all=true) if user.nil?
|
60
|
+
user['time_entries'] || {}
|
61
|
+
end
|
62
|
+
|
63
|
+
def my_workspaces(user=nil)
|
64
|
+
user = me(all=true) if user.nil?
|
65
|
+
user['workspaces'] || {}
|
66
|
+
end
|
67
|
+
|
68
|
+
def create_user(params)
|
69
|
+
params['created_with'] = TogglV8::NAME unless params.has_key?('created_with')
|
70
|
+
requireParams(params, ['email', 'password', 'timezone', 'created_with'])
|
71
|
+
post "signups", { 'user' => params }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module TogglV8
|
2
|
+
class API
|
3
|
+
|
4
|
+
##
|
5
|
+
# ---------
|
6
|
+
# :section: Workspaces
|
7
|
+
#
|
8
|
+
# name : (string, required)
|
9
|
+
# premium : If it's a pro workspace or not.
|
10
|
+
# Shows if someone is paying for the workspace or not (boolean, not required)
|
11
|
+
# at : timestamp that is sent in the response, indicates the time item was last updated
|
12
|
+
|
13
|
+
def workspaces
|
14
|
+
get "workspaces"
|
15
|
+
end
|
16
|
+
|
17
|
+
def clients(workspace_id=nil)
|
18
|
+
if workspace_id.nil?
|
19
|
+
get "clients"
|
20
|
+
else
|
21
|
+
get "workspaces/#{workspace_id}/clients"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def projects(workspace_id, params={})
|
26
|
+
active = params.has_key?(:active) ? "?active=#{params[:active]}" : ""
|
27
|
+
get "workspaces/#{workspace_id}/projects#{active}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def users(workspace_id)
|
31
|
+
get "workspaces/#{workspace_id}/users"
|
32
|
+
end
|
33
|
+
|
34
|
+
def tasks(workspace_id, params={})
|
35
|
+
active = params.has_key?(:active) ? "?active=#{params[:active]}" : ""
|
36
|
+
get "workspaces/#{workspace_id}/tasks#{active}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def tags(workspace_id)
|
40
|
+
get "workspaces/#{workspace_id}/tags"
|
41
|
+
end
|
42
|
+
|
43
|
+
def leave_workspace(workspace_id)
|
44
|
+
delete "workspaces/#{workspace_id}/leave"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,254 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
describe 'ReportsV2' do
|
4
|
+
it 'initializes with api_token' do
|
5
|
+
reports = TogglV8::ReportsV2.new(api_token: Testing::API_TOKEN)
|
6
|
+
env = reports.env
|
7
|
+
expect(env).to_not be nil
|
8
|
+
expect(env['user']['api_token']).to eq Testing::API_TOKEN
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'does not initialize with bogus api_token' do
|
12
|
+
reports = TogglV8::ReportsV2.new(api_token: '4880nqor1orr9n241sn08070q33oq49s')
|
13
|
+
expect { reports.env }.to raise_error(RuntimeError, "HTTP Status: 401")
|
14
|
+
end
|
15
|
+
|
16
|
+
context '.toggl file' do
|
17
|
+
before :each do
|
18
|
+
@tmp_home = mktemp_dir
|
19
|
+
@original_home = Dir.home
|
20
|
+
ENV['HOME'] = @tmp_home
|
21
|
+
end
|
22
|
+
|
23
|
+
after :each do
|
24
|
+
FileUtils.rm_rf(@tmp_home)
|
25
|
+
ENV['HOME'] = @original_home
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'initializes with .toggl file' do
|
29
|
+
toggl_file = File.join(@tmp_home, '.toggl')
|
30
|
+
File.open(toggl_file, 'w') { |file| file.write(Testing::API_TOKEN) }
|
31
|
+
|
32
|
+
reports = TogglV8::ReportsV2.new
|
33
|
+
env = reports.env
|
34
|
+
expect(env).to_not be nil
|
35
|
+
expect(env['user']['api_token']).to eq Testing::API_TOKEN
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'initializes with custom toggl file' do
|
39
|
+
toggl_file = File.join(@tmp_home, 'my_toggl')
|
40
|
+
File.open(toggl_file, 'w') { |file| file.write(Testing::API_TOKEN) }
|
41
|
+
|
42
|
+
reports = TogglV8::ReportsV2.new(toggl_api_file: toggl_file)
|
43
|
+
env = reports.env
|
44
|
+
expect(env).to_not be nil
|
45
|
+
expect(env['user']['api_token']).to eq Testing::API_TOKEN
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'raises error if .toggl file is missing' do
|
49
|
+
expect{ reports = TogglV8::ReportsV2.new }.to raise_error(RuntimeError)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'handles errors' do
|
54
|
+
before :all do
|
55
|
+
@reports = TogglV8::ReportsV2.new(api_token: Testing::API_TOKEN)
|
56
|
+
@reports.workspace_id = @workspace_id
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'surfaces a Warning HTTP header in case of 400 error' do
|
60
|
+
# https://github.com/toggl/toggl_api_docs/blob/master/reports.md#failed-requests
|
61
|
+
expect { @reports.error400 }.to raise_error(RuntimeError,
|
62
|
+
"This URL is intended only for testing")
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'retries a request up to 3 times if a 429 is received' do
|
66
|
+
expect(@reports.conn).to receive(:get).exactly(3).times.and_return(
|
67
|
+
MockResponse.new(429, {}, 'body'))
|
68
|
+
expect { @reports.env }.to raise_error(RuntimeError, "HTTP Status: 429")
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'retries a request after 429' do
|
72
|
+
expect(@reports.conn).to receive(:get).twice.and_return(
|
73
|
+
MockResponse.new(429, {}, 'body'),
|
74
|
+
MockResponse.new(200, {}, 'rev1.2.3'))
|
75
|
+
expect(@reports.revision).to eq('rev1.2.3')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'miscellaneous' do
|
80
|
+
it 'env returns environment' do
|
81
|
+
reports = TogglV8::ReportsV2.new(api_token: Testing::API_TOKEN)
|
82
|
+
reports.workspace_id = @workspace_id
|
83
|
+
env = reports.env
|
84
|
+
expect(env['workspace']).to_not be nil
|
85
|
+
expect(env['user']).to_not be nil
|
86
|
+
expect(env['user']['id']).to eq Testing::USER_ID
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'index returns endpoints' do
|
90
|
+
reports = TogglV8::ReportsV2.new(api_token: Testing::API_TOKEN)
|
91
|
+
reports.workspace_id = @workspace_id
|
92
|
+
index = reports.index
|
93
|
+
expect(index['Welcome to reports api V2. VALID requests are:']).to_not be nil
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'revision has not changed' do
|
97
|
+
reports = TogglV8::ReportsV2.new(api_token: Testing::API_TOKEN)
|
98
|
+
reports.workspace_id = @workspace_id
|
99
|
+
expect(reports.revision).to eq "0.0.38\n-8a007ca"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'project', :pro_account do
|
104
|
+
before :all do
|
105
|
+
@toggl = TogglV8::API.new(Testing::API_TOKEN)
|
106
|
+
@project_name = "Project #{Time.now.iso8601}"
|
107
|
+
@project = @toggl.create_project({
|
108
|
+
'name' => @project_name,
|
109
|
+
'wid' => @workspace_id
|
110
|
+
})
|
111
|
+
end
|
112
|
+
|
113
|
+
after :all do
|
114
|
+
@toggl.delete_project(@project['id'])
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'dashboard' do
|
118
|
+
reports = TogglV8::ReportsV2.new(api_token: Testing::API_TOKEN)
|
119
|
+
reports.workspace_id = @toggl.workspaces.first['id']
|
120
|
+
project_dashboard = reports.project(@project['id'])
|
121
|
+
|
122
|
+
expect(project_dashboard['name']).to eq @project_name
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'blank reports' do
|
127
|
+
before :all do
|
128
|
+
@toggl = TogglV8::API.new(Testing::API_TOKEN)
|
129
|
+
@workspaces = @toggl.workspaces
|
130
|
+
@workspace_id = @workspaces.first['id']
|
131
|
+
@reports = TogglV8::ReportsV2.new(api_token: Testing::API_TOKEN)
|
132
|
+
@reports.workspace_id = @workspace_id
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'summary' do
|
136
|
+
expect(@reports.summary).to eq []
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'weekly' do
|
140
|
+
expect(@reports.weekly).to eq []
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'details' do
|
144
|
+
expect(@reports.details).to eq []
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
context 'reports' do
|
149
|
+
before :all do
|
150
|
+
@toggl = TogglV8::API.new(Testing::API_TOKEN)
|
151
|
+
@workspaces = @toggl.workspaces
|
152
|
+
@workspace_id = @workspaces.first['id']
|
153
|
+
time_entry_info = {
|
154
|
+
'wid' => @workspace_id,
|
155
|
+
'start' => @toggl.iso8601(DateTime.now),
|
156
|
+
'duration' => 77
|
157
|
+
}
|
158
|
+
|
159
|
+
@time_entry = @toggl.create_time_entry(time_entry_info)
|
160
|
+
|
161
|
+
@reports = TogglV8::ReportsV2.new(api_token: Testing::API_TOKEN)
|
162
|
+
@reports.workspace_id = @workspace_id
|
163
|
+
|
164
|
+
@tmp_home = mktemp_dir
|
165
|
+
@original_home = Dir.home
|
166
|
+
ENV['HOME'] = @tmp_home
|
167
|
+
end
|
168
|
+
|
169
|
+
after :all do
|
170
|
+
@toggl.delete_time_entry(@time_entry['id'])
|
171
|
+
|
172
|
+
FileUtils.rm_rf(@tmp_home)
|
173
|
+
ENV['HOME'] = @original_home
|
174
|
+
end
|
175
|
+
|
176
|
+
context 'JSON reports' do
|
177
|
+
it 'summary' do
|
178
|
+
summary = @reports.summary
|
179
|
+
expect(summary.length).to eq 1
|
180
|
+
expect(summary.first['time']).to eq 77000
|
181
|
+
expect(summary.first['items'].length).to eq 1
|
182
|
+
expect(summary.first['items'].first['time']).to eq 77000
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'weekly' do
|
186
|
+
weekly = @reports.weekly
|
187
|
+
expect(weekly.length).to eq 1
|
188
|
+
expect(weekly.first['details'].first['title']['user']).to eq Testing::USERNAME
|
189
|
+
expect(weekly.first['totals'][7]).to eq 77000
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'details' do
|
193
|
+
details = @reports.details
|
194
|
+
expect(details.length).to eq 1
|
195
|
+
expect(details.first['user']).to eq Testing::USERNAME
|
196
|
+
expect(details.first['dur']).to eq 77000
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
context 'CSV reports' do
|
201
|
+
it 'summary' do
|
202
|
+
filename = File.join(@tmp_home, 'summary.csv')
|
203
|
+
summary = @reports.write_summary(filename)
|
204
|
+
expect(file_contains(filename, /00:01:17/))
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'weekly' do
|
208
|
+
filename = File.join(@tmp_home, 'weekly.csv')
|
209
|
+
weekly = @reports.write_weekly(filename)
|
210
|
+
expect(file_contains(filename, /00:01:17/))
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'details' do
|
214
|
+
filename = File.join(@tmp_home, 'details.csv')
|
215
|
+
details = @reports.write_details(filename)
|
216
|
+
expect(file_contains(filename, /00:01:17/))
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
context 'PDF reports' do
|
221
|
+
it 'summary' do
|
222
|
+
filename = File.join(@tmp_home, 'summary.pdf')
|
223
|
+
summary = @reports.write_summary(filename)
|
224
|
+
expect(file_is_pdf(filename))
|
225
|
+
end
|
226
|
+
|
227
|
+
it 'weekly' do
|
228
|
+
filename = File.join(@tmp_home, 'weekly.pdf')
|
229
|
+
weekly = @reports.write_weekly(filename)
|
230
|
+
expect(file_is_pdf(filename))
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'details' do
|
234
|
+
filename = File.join(@tmp_home, 'details.pdf')
|
235
|
+
details = @reports.write_details(filename)
|
236
|
+
expect(file_is_pdf(filename))
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
context 'XLS reports' do
|
241
|
+
it 'summary' do
|
242
|
+
filename = File.join(@tmp_home, 'summary.xls')
|
243
|
+
summary = @reports.write_summary(filename)
|
244
|
+
expect(file_is_xls(filename))
|
245
|
+
end
|
246
|
+
|
247
|
+
it 'details' do
|
248
|
+
filename = File.join(@tmp_home, 'details.xls')
|
249
|
+
details = @reports.write_details(filename)
|
250
|
+
expect(file_is_xls(filename))
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
describe 'Clients' do
|
2
|
+
before :all do
|
3
|
+
@toggl = TogglV8::API.new(Testing::API_TOKEN)
|
4
|
+
@workspaces = @toggl.workspaces
|
5
|
+
@workspace_id = @workspaces.first['id']
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'gets {} if there are no clients' do
|
9
|
+
client = @toggl.clients
|
10
|
+
expect(client).to be_empty
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'gets {} if there are no workspace clients' do
|
14
|
+
client = @toggl.clients(@workspace_id)
|
15
|
+
expect(client).to be_empty
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'new client' do
|
19
|
+
before :all do
|
20
|
+
@client = @toggl.create_client({ 'name' => 'new client +1', 'wid' => @workspace_id })
|
21
|
+
client_ids = @toggl.my_clients.map { |c| c['id'] }
|
22
|
+
expect(client_ids).to eq [ @client['id'] ]
|
23
|
+
end
|
24
|
+
|
25
|
+
after :all do
|
26
|
+
TogglV8SpecHelper.delete_all_clients(@toggl)
|
27
|
+
clients = @toggl.my_clients
|
28
|
+
expect(clients).to be_empty
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'gets a client' do
|
32
|
+
client_ids = @toggl.clients.map { |c| c['id'] }
|
33
|
+
expect(client_ids).to eq [ @client['id'] ]
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'gets a workspace client' do
|
37
|
+
client_ids = @toggl.clients(@workspace_id).map { |c| c['id'] }
|
38
|
+
expect(client_ids).to eq [ @client['id'] ]
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'multiple clients' do
|
42
|
+
before :all do
|
43
|
+
@client2 = @toggl.create_client({ 'name' => 'new client 2', 'wid' => @workspace_id })
|
44
|
+
end
|
45
|
+
|
46
|
+
after :all do
|
47
|
+
@toggl.delete_client(@client2['id'])
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'gets clients' do
|
51
|
+
client_ids = @toggl.clients.map { |c| c['id'] }
|
52
|
+
expect(client_ids).to match_array [ @client['id'], @client2['id'] ]
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'gets workspace clients' do
|
56
|
+
client_ids = @toggl.clients(@workspace_id).map { |c| c['id'] }
|
57
|
+
expect(client_ids).to match_array [ @client['id'], @client2['id'] ]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'creates a client' do
|
62
|
+
expect(@client).to_not be nil
|
63
|
+
expect(@client['name']).to eq 'new client +1'
|
64
|
+
expect(@client['notes']).to eq nil
|
65
|
+
expect(@client['wid']).to eq @workspace_id
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'gets client data' do
|
69
|
+
client = @toggl.get_client(@client['id'])
|
70
|
+
expect(client).to_not be nil
|
71
|
+
expect(client['name']).to eq @client['name']
|
72
|
+
expect(client['wid']).to eq @client['wid']
|
73
|
+
expect(client['notes']).to eq @client['notes']
|
74
|
+
expect(client['at']).to_not be nil
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'client projects' do
|
78
|
+
it 'gets {} if there are no client projects' do
|
79
|
+
projects = @toggl.get_client_projects(@client['id'])
|
80
|
+
expect(projects).to be_empty
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'new client projects' do
|
84
|
+
before :all do
|
85
|
+
@project = @toggl.create_project({ 'name' => 'project', 'wid' => @workspace_id, 'cid' => @client['id'] })
|
86
|
+
end
|
87
|
+
|
88
|
+
after :all do
|
89
|
+
TogglV8SpecHelper.delete_all_projects(@toggl)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'gets a client project' do
|
93
|
+
projects = @toggl.get_client_projects(@client['id'])
|
94
|
+
project_ids = projects.map { |p| p['id'] }
|
95
|
+
expect(project_ids).to eq [ @project['id'] ]
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'gets multiple client projects' do
|
99
|
+
project2 = @toggl.create_project({ 'name' => 'project2', 'wid' => @workspace_id, 'cid' => @client['id'] })
|
100
|
+
|
101
|
+
projects = @toggl.get_client_projects(@client['id'])
|
102
|
+
project_ids = projects.map { |p| p['id'] }
|
103
|
+
expect(project_ids).to match_array [ @project['id'], project2['id'] ]
|
104
|
+
|
105
|
+
@toggl.delete_project(project2['id'])
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'updated client' do
|
112
|
+
before :each do
|
113
|
+
@client = @toggl.create_client({ 'name' => 'client to update', 'wid' => @workspace_id })
|
114
|
+
end
|
115
|
+
|
116
|
+
after :each do
|
117
|
+
@toggl.delete_client(@client['id'])
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'updates client data' do
|
121
|
+
new_values = {
|
122
|
+
'name' => 'CLIENT-NEW',
|
123
|
+
'notes' => 'NOTES-NEW',
|
124
|
+
}
|
125
|
+
|
126
|
+
client = @toggl.update_client(@client['id'], new_values)
|
127
|
+
expect(client).to include(new_values)
|
128
|
+
end
|
129
|
+
|
130
|
+
# :nocov:
|
131
|
+
# It appears hourly rate is no longer tied to a client despite the docs:
|
132
|
+
# https://github.com/toggl/toggl_api_docs/blob/master/chapters/clients.md#clients
|
133
|
+
xit 'updates Pro client data', :pro_account do
|
134
|
+
new_values = {
|
135
|
+
'hrate' => '7.77',
|
136
|
+
'cur' => 'USD',
|
137
|
+
}
|
138
|
+
client = @toggl.update_client(@client['id'], new_values)
|
139
|
+
|
140
|
+
client = @toggl.get_client(@client['id'])
|
141
|
+
expect(client).to include(new_values)
|
142
|
+
end
|
143
|
+
# :nocov:
|
144
|
+
end
|
145
|
+
end
|