sfctl 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '01538701ef7e4ff9999297400cb4853751ad2b45485f18524e9545416e34e1a7'
4
- data.tar.gz: 1ac3e8c834236ceb56556770057e99e5644c7e2b4a86e63daa8078239cca37de
3
+ metadata.gz: 87640e37bddf52afff13b5ac880334429e8357308c4ca069df10cb06d5627463
4
+ data.tar.gz: 7431952f8f7d62c6ce5676276f6dc50218389c6d3433e8886e08351f0670dee6
5
5
  SHA512:
6
- metadata.gz: fccda9b85147a7373c83426de924435d56221fb350547b6957b8f760f3669ec529d21f04c10c9dbb566c35586be35c97788d2e0b28f236e7a00a50b2c7efeccb
7
- data.tar.gz: 4567297fec6b1a36896c2322ffec80ead48b532d558b2804c4c7859dfe67fbc5ecb00eafc84854e3bec965fc1f6118bfdde08df35d8c0a637d3f2489d388f686
6
+ metadata.gz: 5d4518ccdd8dfb1595954e19169402db62511a6be21b3011c082f1bf67661fa3156c44aedd80afdc79ab2fe5a5d991068127b51af02080eef644478f64c93cd2
7
+ data.tar.gz: 4ec95937e28e42fb82fc289851eadb46d475c2aa59fc9d6819f744e9df6a0ecf266596882cd70828d7aec4e67385008c7117e8552aee8f78811c98a37e5c018c
data/.gitignore CHANGED
@@ -10,3 +10,5 @@
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
12
  .DS_Store
13
+ sfctl-*.gem
14
+ /.sflink
data/.rubocop.yml CHANGED
@@ -31,6 +31,9 @@ Metrics/BlockLength:
31
31
  Metrics/AbcSize:
32
32
  Max: 20
33
33
 
34
+ Metrics/ClassLength:
35
+ Enabled: false
36
+
34
37
  Metrics/MethodLength:
35
38
  Max: 20
36
39
 
data/README.md CHANGED
@@ -21,13 +21,11 @@ Flags:
21
21
 
22
22
  ## Installing `sfctl`
23
23
 
24
- ### Using a Package Manager (Preferred)
24
+ ### Using Ruby Gems (Preferred)
25
25
 
26
- More to come.
27
-
28
- ### Git
29
-
30
- More to come.
26
+ ```
27
+ gem install sfctl
28
+ ```
31
29
 
32
30
  ## Authentication
33
31
 
@@ -109,8 +107,6 @@ We will provide a couple of integrations but also open up for plugins later on t
109
107
  As of today we support:
110
108
 
111
109
  - Toggl
112
- - Harvest
113
- - Clockify
114
110
 
115
111
  Another advantage of this approach is, that you think of any automation ⚒ you like to support your processes.
116
112
 
data/lib/sfctl/command.rb CHANGED
@@ -10,7 +10,7 @@ module Sfctl
10
10
  CONFIG_FILENAME = '.sfctl'
11
11
  CONFIG_PATH = "#{Dir.home}/#{CONFIG_FILENAME}"
12
12
  LINK_CONFIG_FILENAME = '.sflink'
13
- LINK_CONFIG_PATH = "#{Dir.home}/#{LINK_CONFIG_FILENAME}"
13
+ LINK_CONFIG_PATH = "#{Dir.pwd}/#{LINK_CONFIG_FILENAME}"
14
14
 
15
15
  TOGGL_PROVIDER = 'toggl'
16
16
  PROVIDERS_LIST = [
@@ -22,12 +22,12 @@ module Sfctl
22
22
  which can be created on the profile page of your account.
23
23
  HEREDOC
24
24
  method_option :help, aliases: '-h', type: :boolean
25
- def init(access_token)
25
+ def init(*)
26
26
  if options[:help]
27
27
  invoke :help, ['init']
28
28
  else
29
29
  require_relative 'auth/init'
30
- Sfctl::Commands::Auth::Init.new(access_token, options).execute
30
+ Sfctl::Commands::Auth::Init.new(options).execute
31
31
  end
32
32
  end
33
33
  end
@@ -1,31 +1,29 @@
1
- # frozen_string_literal: true
2
-
3
1
  require_relative '../../command'
4
2
  require_relative '../../starfish'
5
3
  require 'pastel'
4
+ require 'tty-prompt'
6
5
  require 'tty-spinner'
7
6
 
8
7
  module Sfctl
9
8
  module Commands
10
9
  class Auth
11
10
  class Init < Sfctl::Command
12
- def initialize(access_token, options)
13
- @access_token = access_token
11
+ def initialize(options)
14
12
  @options = options
15
-
16
13
  @pastel = Pastel.new(enabled: !@options['no-color'])
17
14
  end
18
15
 
19
16
  def execute(output: $stdout)
17
+ access_token = ::TTY::Prompt.new.ask("Access token(#{@options['starfish-host']}):", required: true)
20
18
  spinner = ::TTY::Spinner.new('[:spinner] Checking token ...')
21
19
  spinner.auto_spin
22
- token_valid? ? update_config!(spinner, output) : render_error(spinner, output)
20
+ token_valid?(access_token) ? update_config!(spinner, output, access_token) : render_error(spinner, output)
23
21
  end
24
22
 
25
23
  private
26
24
 
27
- def token_valid?
28
- Starfish.check_authorization(@options['starfish-host'], @access_token)
25
+ def token_valid?(access_token)
26
+ Starfish.check_authorization(@options['starfish-host'], access_token)
29
27
  end
30
28
 
31
29
  def token_accepted_message
@@ -36,8 +34,8 @@ module Sfctl
36
34
  @pastel.red('Token is not accepted, please make sure you copy and paste it correctly.')
37
35
  end
38
36
 
39
- def update_config!(spinner, output)
40
- config.set :access_token, value: @access_token
37
+ def update_config!(spinner, output, access_token)
38
+ config.set :access_token, value: access_token
41
39
  save_config!
42
40
  spinner.success
43
41
  output.puts token_accepted_message
@@ -1,7 +1,10 @@
1
+ require 'date'
1
2
  require 'pastel'
3
+ require 'tty-spinner'
2
4
  require 'tty-prompt'
3
5
  require_relative '../../../command'
4
6
  require_relative '../../../starfish'
7
+ require_relative '../../../toggl'
5
8
 
6
9
  module Sfctl
7
10
  module Commands
@@ -11,10 +14,10 @@ module Sfctl
11
14
  def initialize(options)
12
15
  @options = options
13
16
  @pastel = Pastel.new(enabled: !@options['no-color'])
14
- @prompt = ::TTY::Prompt.new
17
+ @prompt = ::TTY::Prompt.new(help_color: :cyan)
15
18
  end
16
19
 
17
- def execute(output: $stdout) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
20
+ def execute(output: $stdout) # rubocop:disable Metrics/AbcSize
18
21
  return if !config_present?(output) || !link_config_present?(output)
19
22
 
20
23
  ltoken = access_token
@@ -33,24 +36,33 @@ module Sfctl
33
36
 
34
37
  provider = @prompt.select('Select provider:', PROVIDERS_LIST)
35
38
 
36
- assignment_name = select_assignment(assignments)
39
+ assignment_obj = select_assignment(assignments)
37
40
 
38
41
  case provider
39
42
  when TOGGL_PROVIDER
40
- setup_toggl_connection!(assignment_name)
43
+ setup_toggl_connection!(output, assignment_obj)
41
44
  end
45
+ end
46
+
47
+ private
42
48
 
49
+ def clear_conf_and_print_success!(output)
50
+ delete_providers_from_link_config!
43
51
  save_link_config!
44
52
 
45
53
  output.puts @pastel.green('Connection successfully added.')
46
54
  end
47
55
 
48
- private
56
+ def delete_providers_from_link_config!
57
+ config.set(:providers, value: '')
58
+ config.delete(:providers)
59
+ end
49
60
 
50
61
  def select_assignment(assignments)
51
62
  @prompt.select('Select assignment:') do |menu|
52
63
  assignments.each.with_index do |asmnt, i|
53
- menu.choice name: "#{i + 1}. #{asmnt['name']} / #{asmnt['service']}", value: asmnt['name']
64
+ menu.choice name: "#{i + 1}. #{asmnt['name']} / #{asmnt['service']}",
65
+ value: { 'id' => asmnt['id'], 'name' => asmnt['name'], 'service' => asmnt['service'] }
54
66
  end
55
67
  end
56
68
  end
@@ -58,24 +70,81 @@ module Sfctl
58
70
  def filter_assignments(list)
59
71
  return list if config.fetch(:connections).nil?
60
72
 
61
- added_assignments_name = config.fetch(:connections).keys
62
- list.delete_if { |h| added_assignments_name.include?(h['name']) }
73
+ added_assignments_ids = config.fetch(:connections).keys
74
+ list.delete_if { |h| added_assignments_ids.include?(h['id'].to_s) }
63
75
  list
64
76
  end
65
77
 
66
- def setup_toggl_connection!(assignment_name)
67
- workspace_id = @prompt.ask('Workspace ID (required):', required: true)
68
- project_ids = @prompt.ask('Project IDs (required / comma separated):', required: true)
69
- task_ids = @prompt.ask('Task IDs (optional / comma separated):') || ''
70
- billable = @prompt.select('Billable? (required)', %w[yes no both])
71
- rounding = @prompt.select('Rounding? (required)', %w[on off])
72
-
73
- config.set("connections.#{assignment_name}.provider", value: TOGGL_PROVIDER)
74
- config.set("connections.#{assignment_name}.workspace_id", value: workspace_id)
75
- config.set("connections.#{assignment_name}.project_ids", value: project_ids)
76
- config.set("connections.#{assignment_name}.task_ids", value: task_ids)
77
- config.set("connections.#{assignment_name}.billable", value: billable)
78
- config.set("connections.#{assignment_name}.rounding", value: rounding)
78
+ def setup_toggl_connection!(output, assignment_obj) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
79
+ spinner = ::TTY::Spinner.new('[:spinner] Loading ...')
80
+
81
+ assignment_id = assignment_obj['id']
82
+ toggl_token = read_link_config['providers'][TOGGL_PROVIDER]['access_token']
83
+
84
+ spinner.auto_spin
85
+ _success, workspaces = Toggl.workspaces(toggl_token)
86
+ spinner.pause
87
+ output.puts
88
+ workspace = @prompt.select('Please select Workspace:') do |menu|
89
+ workspaces.each do |w|
90
+ menu.choice name: w['name'], value: w
91
+ end
92
+ end
93
+ workspace_id = workspace['id']
94
+
95
+ spinner.resume
96
+ _success, projects = Toggl.workspace_projects(toggl_token, workspace_id)
97
+
98
+ if projects.nil? || projects.empty?
99
+ spinner.stop
100
+ error_message = "There is no projects. Please visit #{TOGGL_PROVIDER} and create them before continue."
101
+ output.puts @pastel.red(error_message)
102
+ return
103
+ end
104
+
105
+ spinner.pause
106
+ output.puts
107
+ project_ids = @prompt.multi_select('Please select Projects:', min: 1) do |menu|
108
+ projects.each do |project|
109
+ menu.choice project['name'], project['id']
110
+ end
111
+ end
112
+
113
+ spinner.resume
114
+ tasks_objs = []
115
+ project_ids.each do |pj_id|
116
+ _success, tasks = Toggl.project_tasks(toggl_token, pj_id)
117
+ tasks_objs << tasks
118
+ end
119
+ tasks_objs.flatten!
120
+ tasks_objs.compact!
121
+ output.puts
122
+ spinner.success
123
+ tasks_ids = []
124
+ if tasks_objs.length.positive?
125
+ tasks_ids = @prompt.multi_select('Please select Tasks(by last 3 months):') do |menu|
126
+ tasks_objs.each do |to|
127
+ menu.choice to['name'], to['id']
128
+ end
129
+ end
130
+ else
131
+ output.puts @pastel.yellow("You don't have tasks. Continue...")
132
+ end
133
+
134
+ billable = @prompt.select('Billable?', %w[yes no both])
135
+
136
+ rounding = @prompt.select('Rounding?', %w[on off])
137
+
138
+ config.set("connections.#{assignment_id}.name", value: assignment_obj['name'])
139
+ config.set("connections.#{assignment_id}.service", value: assignment_obj['service'])
140
+ config.set("connections.#{assignment_id}.provider", value: TOGGL_PROVIDER)
141
+ config.set("connections.#{assignment_id}.workspace_id", value: workspace_id.to_s)
142
+ config.set("connections.#{assignment_id}.project_ids", value: project_ids.join(', '))
143
+ config.set("connections.#{assignment_id}.task_ids", value: tasks_ids.join(', '))
144
+ config.set("connections.#{assignment_id}.billable", value: billable)
145
+ config.set("connections.#{assignment_id}.rounding", value: rounding)
146
+
147
+ clear_conf_and_print_success!(output)
79
148
  end
80
149
  end
81
150
  end
@@ -28,22 +28,23 @@ module Sfctl
28
28
  private
29
29
 
30
30
  def print_connections(output)
31
- config.fetch(:connections).each_key do |assignment_name|
32
- case config.fetch(:connections, assignment_name, :provider)
31
+ config.fetch(:connections).each_key do |assignment_id|
32
+ case config.fetch(:connections, assignment_id, :provider)
33
33
  when TOGGL_PROVIDER
34
- print_toggl_connection!(output, assignment_name)
34
+ print_toggl_connection!(output, assignment_id)
35
35
  end
36
36
  end
37
37
  end
38
38
 
39
- def print_toggl_connection!(output, assignment_name)
40
- output.puts "Connection: #{assignment_name}"
39
+ def print_toggl_connection!(output, assignment_id) # rubocop:disable Metrics/AbcSize
40
+ output.puts "Connection: #{config.fetch(:connections, assignment_id, :name)}"
41
+ output.puts " service: #{config.fetch(:connections, assignment_id, :service)}"
41
42
  output.puts " provider: #{TOGGL_PROVIDER}"
42
- output.puts " workspace_id: #{config.fetch(:connections, assignment_name, :workspace_id)}"
43
- output.puts " project_ids: #{config.fetch(:connections, assignment_name, :project_ids)}"
44
- output.puts " task_ids: #{config.fetch(:connections, assignment_name, :task_ids)}"
45
- output.puts " billable: #{config.fetch(:connections, assignment_name, :billable)}"
46
- output.puts " rounding: #{config.fetch(:connections, assignment_name, :rounding)}"
43
+ output.puts " workspace_id: #{config.fetch(:connections, assignment_id, :workspace_id)}"
44
+ output.puts " project_ids: #{config.fetch(:connections, assignment_id, :project_ids)}"
45
+ output.puts " task_ids: #{config.fetch(:connections, assignment_id, :task_ids)}"
46
+ output.puts " billable: #{config.fetch(:connections, assignment_id, :billable)}"
47
+ output.puts " rounding: #{config.fetch(:connections, assignment_id, :rounding)}"
47
48
  output.puts
48
49
  end
49
50
  end
@@ -12,13 +12,11 @@ module Sfctl
12
12
  end
13
13
 
14
14
  def execute(output: $stdout)
15
- read_link_config
15
+ return unless config_present?(output)
16
16
 
17
17
  PROVIDERS_LIST.each do |provider|
18
18
  read(provider, output)
19
19
  end
20
- rescue TTY::Config::ReadError
21
- output.puts @pastel.yellow('Please initialize time before continue.')
22
20
  end
23
21
 
24
22
  private
@@ -13,7 +13,7 @@ module Sfctl
13
13
  end
14
14
 
15
15
  def execute(output: $stdout)
16
- read_link_config
16
+ return unless config_present?(output)
17
17
 
18
18
  prompt = ::TTY::Prompt.new
19
19
  provider = prompt.select('Setting up:', PROVIDERS_LIST)
@@ -24,8 +24,6 @@ module Sfctl
24
24
  when TOGGL_PROVIDER
25
25
  setup_toggl_provider!(output, prompt)
26
26
  end
27
- rescue TTY::Config::ReadError
28
- output.puts @pastel.yellow('Please initialize time before continue.')
29
27
  end
30
28
 
31
29
  private
@@ -37,7 +35,7 @@ module Sfctl
37
35
 
38
36
  def save_toggl_config!(output, access_token)
39
37
  config.set("providers.#{TOGGL_PROVIDER}.access_token", value: access_token)
40
- save_link_config!
38
+ save_config!
41
39
  output.puts @pastel.green('Everything saved.')
42
40
  end
43
41
 
@@ -13,7 +13,7 @@ module Sfctl
13
13
  end
14
14
 
15
15
  def execute(output: $stdout)
16
- read_link_config
16
+ return unless config_present?(output)
17
17
 
18
18
  prompt = ::TTY::Prompt.new
19
19
  provider = prompt.select('Unsetting:', PROVIDERS_LIST)
@@ -23,8 +23,6 @@ module Sfctl
23
23
  elsif prompt.yes?('Do you want to remove the delete the configuration?')
24
24
  remove_provider!(provider, output)
25
25
  end
26
- rescue TTY::Config::ReadError
27
- output.puts @pastel.yellow('Please initialize time before continue.')
28
26
  end
29
27
 
30
28
  private
@@ -33,7 +31,7 @@ module Sfctl
33
31
  providers = config.fetch(:providers)
34
32
  providers.delete(provider)
35
33
  config.set(:providers, value: providers)
36
- save_link_config!
34
+ save_config!
37
35
  output.puts @pastel.green("Configuration for provider [#{provider}] was successfully deleted.")
38
36
  end
39
37
  end
@@ -10,7 +10,7 @@ require_relative '../../toggl'
10
10
  module Sfctl
11
11
  module Commands
12
12
  class Time
13
- class Sync < Sfctl::Command # rubocop:disable Metrics/ClassLength
13
+ class Sync < Sfctl::Command
14
14
  def initialize(options)
15
15
  @options = options
16
16
  @pastel = Pastel.new(enabled: !@options['no-color'])
@@ -20,31 +20,44 @@ module Sfctl
20
20
  def execute(output: $stdout)
21
21
  return if !config_present?(output) || !link_config_present?(output)
22
22
 
23
- success, data = Starfish.account_assignments(@options['starfish-host'], @options['all'], access_token)
24
- unless success
25
- output.puts @pastel.red('Something went wrong. Unable to fetch assignments')
23
+ if read_link_config['connections'].length.zero?
24
+ output.puts @pastel.red('Please add a connection before continue.')
26
25
  return
27
26
  end
28
27
 
29
- sync_assignments(output, assignments_to_sync(data['assignments']))
28
+ sync_assignments(output, assignments_to_sync)
30
29
  rescue ThreadError, JSON::ParserError
30
+ output.puts
31
31
  output.puts @pastel.red('Something went wrong.')
32
32
  end
33
33
 
34
34
  private
35
35
 
36
- def assignments_to_sync(assignments)
37
- assignment_name = select_assignment(assignments)
36
+ def assignments_from_connections
37
+ read_link_config['connections'].map do |con|
38
+ id = con[0]
39
+ asmnt = con[1]
40
+ {
41
+ 'id' => id,
42
+ 'name' => asmnt['name'],
43
+ 'service' => asmnt['service'] || '-'
44
+ }
45
+ end
46
+ end
47
+
48
+ def assignments_to_sync
49
+ assignments = assignments_from_connections
50
+ assignment_id = select_assignment(assignments)
38
51
 
39
- return assignments if assignment_name == 'all'
52
+ return assignments if assignment_id == 'all'
40
53
 
41
- assignments.select { |a| a['name'] == assignment_name }.to_a
54
+ assignments.select { |a| a['id'].to_s == assignment_id.to_s }.to_a
42
55
  end
43
56
 
44
57
  def select_assignment(assignments)
45
58
  @prompt.select('Which assignment do you want to sync?') do |menu|
46
59
  assignments.each do |asmnt|
47
- menu.choice name: "#{asmnt['name']} / #{asmnt['service']}", value: asmnt['name']
60
+ menu.choice name: "#{asmnt['name']} / #{asmnt['service']}", value: asmnt['id'].to_s
48
61
  end
49
62
  menu.choice name: 'All', value: 'all'
50
63
  end
@@ -52,15 +65,15 @@ module Sfctl
52
65
 
53
66
  def sync_assignments(output, list)
54
67
  list.each do |assignment|
55
- assignment_name = assignment['name']
56
- connection = read_link_config['connections'].select { |c| c == assignment_name }
68
+ assignment_id = assignment['id'].to_s
69
+ connection = read_link_config['connections'].select { |c| c == assignment_id }
57
70
 
58
71
  if connection.empty?
59
- output.puts @pastel.red("Unable to find a connection for assignment \"#{assignment_name}\"")
72
+ output.puts @pastel.red("Unable to find a connection for assignment \"#{assignment['name']}\"")
60
73
  next
61
74
  end
62
75
 
63
- sync(output, assignment, connection[assignment_name])
76
+ sync(output, assignment, connection[assignment_id])
64
77
  end
65
78
  end
66
79
 
@@ -133,56 +146,66 @@ module Sfctl
133
146
  output.puts
134
147
  output.puts
135
148
 
136
- time_entries
149
+ time_entries['data']
137
150
  end
138
151
 
139
152
  def time_entries_table_rows(time_entries)
140
- rows = time_entries.map do |te|
153
+ rows = time_entries['data'].sort_by { |te| te['start'] }.map do |te|
141
154
  [
142
155
  Date.parse(te['start']).to_s,
143
156
  te['description'],
144
- "#{humanize_duration(te['duration'])}h"
157
+ "#{humanize_duration(te['dur'])}h"
145
158
  ]
146
159
  end
147
- rows.push(['Total:', '', "#{humanize_duration(time_entries.map { |te| te['duration'] }.sum)}h"])
160
+ rows.push(['Total:', '', "#{humanize_duration(time_entries['total_grand'])}h"])
148
161
  rows
149
162
  end
150
163
 
151
164
  def get_toggle_time_entries(next_report, connection)
152
- _success, time_entries = Toggl.time_entries(
165
+ _success, data = Toggl.time_entries(
153
166
  read_link_config['providers'][TOGGL_PROVIDER]['access_token'], time_entries_params(next_report, connection)
154
167
  )
155
- unless connection['task_ids'].empty?
156
- time_entries.delete_if { |te| !connection['task_ids'].include?(te['id'].to_s) }
157
- end
158
168
 
159
- time_entries
169
+ data
160
170
  end
161
171
 
162
172
  def time_entries_params(next_report, connection)
163
173
  start_date = Date.parse("#{next_report['year']}-#{next_report['month']}-01")
164
174
  end_date = start_date.next_month.prev_day
165
- {
166
- wid: connection['workspace_id'],
167
- pid: connection['project_ids'],
168
- start_date: start_date.to_datetime.to_s,
169
- end_date: "#{end_date}T23:59:59+00:00"
175
+ params = {
176
+ workspace_id: connection['workspace_id'],
177
+ project_ids: connection['project_ids'],
178
+ billable: connection['billable'],
179
+ rounding: connection['rounding'],
180
+ since: start_date.to_s,
181
+ until: end_date.to_s
170
182
  }
183
+ params[:task_ids] = connection['task_ids'] if connection['task_ids'].length.positive?
184
+ params
171
185
  end
172
186
 
173
- def humanize_duration(seconds)
187
+ def humanize_duration(milliseconds)
188
+ return '0' if milliseconds.nil?
189
+
190
+ seconds = milliseconds / 1000
174
191
  minutes = seconds / 60
175
192
  int = (minutes / 60).ceil
176
193
  dec = minutes % 60
177
194
  amount = (dec * 100) / 60
178
- amount = dec.zero? ? '' : ".#{amount}"
195
+ amount = if dec.zero?
196
+ ''
197
+ elsif amount.to_s.length == 1
198
+ ".0#{amount}"
199
+ else
200
+ ".#{amount}"
201
+ end
179
202
  "#{int}#{amount}"
180
203
  end
181
204
 
182
205
  def assignment_items(time_entries)
183
206
  time_entries.map do |te|
184
207
  {
185
- time: humanize_duration(te['duration']),
208
+ time: humanize_duration(te['dur']).to_f,
186
209
  date: Date.parse(te['start']).to_s,
187
210
  comment: te['description']
188
211
  }
data/lib/sfctl/toggl.rb CHANGED
@@ -3,13 +3,16 @@ require 'json'
3
3
 
4
4
  module Sfctl
5
5
  module Toggl
6
- def self.conn(token)
6
+ DEFAULT_API_PATH = 'api/v8/'.freeze
7
+ REPORTS_API_PATH = 'reports/api/v2/'.freeze
8
+
9
+ def self.conn(token, api = 'default')
7
10
  raise 'Please set toggl provider before continue.' if token.nil?
8
11
 
9
- headers = {
10
- 'Content-Type' => 'application/json'
11
- }
12
- Faraday.new(url: "https://#{token}:api_token@www.toggl.com/api/v8/", headers: headers) do |builder|
12
+ api_path = api == 'reports' ? REPORTS_API_PATH : DEFAULT_API_PATH
13
+
14
+ headers = { 'Content-Type' => 'application/json' }
15
+ Faraday.new(url: "https://#{token}:api_token@www.toggl.com/#{api_path}", headers: headers) do |builder|
13
16
  builder.request :retry
14
17
  builder.adapter :net_http
15
18
  end
@@ -19,8 +22,27 @@ module Sfctl
19
22
  [response.status == 200, JSON.parse(response.body)]
20
23
  end
21
24
 
25
+ def self.workspaces(token)
26
+ response = conn(token).get('workspaces')
27
+ parsed_response(response)
28
+ end
29
+
30
+ def self.workspace_projects(token, workspace_id)
31
+ response = conn(token).get("workspaces/#{workspace_id}/projects")
32
+ parsed_response(response)
33
+ end
34
+
35
+ def self.project_tasks(token, project_id)
36
+ response = conn(token).get("workspaces/#{project_id}/tasks")
37
+
38
+ return [] if response.body.length.zero?
39
+
40
+ parsed_response(response)
41
+ end
42
+
22
43
  def self.time_entries(token, params)
23
- response = conn(token).get('time_entries', params)
44
+ params[:user_agent] = 'api_test'
45
+ response = conn(token, 'reports').get('details', params)
24
46
  parsed_response(response)
25
47
  end
26
48
  end
data/lib/sfctl/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Sfctl
2
- VERSION = '0.0.1'.freeze
2
+ VERSION = '0.0.2'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sfctl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Serhii Rudik
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2020-04-08 00:00:00.000000000 Z
12
+ date: 2020-04-15 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description:
15
15
  email: