sfctl 0.0.1 → 0.0.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.
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: