TokiCLI 0.0.9 → 0.1.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.
@@ -1,10 +1,12 @@
1
1
  require 'json'
2
2
  require 'rest_client'
3
- module ADNAuthorize
3
+ module TokiCLI
4
+ CLIENT_ID = 'm6AccJFM56ENCn58Vde9cSg3uSpbvAAs'
5
+ CALLBACK_URL = 'http://aya.io/toki_cli/auth.html'
4
6
  class Authorize
5
- def initialize
6
- @auth_url = "https://account.app.net/oauth/authenticate?client_id=#{TokiCLI::Toki::CLIENT_ID}&response_type=token&redirect_uri=#{TokiCLI::Toki::CALLBACK_URL}&scope=basic,messages&include_marker=1"
7
- @home = Dir.home + "/.TokiCLI"
7
+ def initialize home
8
+ @auth_url = "https://account.app.net/oauth/authenticate?client_id=#{TokiCLI::CLIENT_ID}&response_type=token&redirect_uri=#{TokiCLI::CALLBACK_URL}&scope=basic,messages&include_marker=1"
9
+ @home = home
8
10
  end
9
11
 
10
12
  def authorize
@@ -0,0 +1,81 @@
1
+ # encoding: utf-8
2
+ module TokiCLI
3
+ class Export
4
+
5
+ def initialize toki, view
6
+ @toki = toki
7
+ @view = view
8
+ end
9
+
10
+ def apps_total options, apps, type
11
+ arr = []
12
+ apps['data']['apps'].each do |obj|
13
+ arr << {
14
+ bundle: obj['bundle'],
15
+ name: obj['name'],
16
+ total: {
17
+ seconds: obj['total']['seconds'],
18
+ time: @view.readable_time(obj['total']['time'])
19
+ }
20
+ }
21
+ end
22
+ save options, arr, "toki-#{type}__#{Time.now.to_s[0..9]}"
23
+ end
24
+
25
+ def log options, log, type
26
+ arr = []
27
+ temp = log['data']['log'].map do |obj|
28
+ [obj[1]['start'], obj[1]['duration']['seconds'], @view.readable_time(obj[1]['duration']['time']), obj[0]]
29
+ end
30
+ temp.sort_by! {|obj| obj[0]}
31
+ temp.each do |obj|
32
+ arr << {
33
+ start: obj[0],
34
+ duration: {
35
+ seconds: obj[1],
36
+ time: obj[2]
37
+ },
38
+ sync_id: obj[3]
39
+ }
40
+ end
41
+ save_log options, arr, "toki-#{type}__#{Time.now.to_s[0..9]}"
42
+ end
43
+
44
+ private
45
+
46
+ def save options, data, filename
47
+ case
48
+ when options[:json]
49
+ name = @toki.helpers.toki_path + "/#{filename}.json"
50
+ File.write(name, data.to_json)
51
+ when options[:csv]
52
+ name = @toki.helpers.toki_path + "/#{filename}.csv"
53
+ CSV.open(name, "wb") do |csv|
54
+ csv << ['Bundle Identifier', 'Name', 'Total seconds', 'Total time']
55
+ data.each {|line| csv << [line[:bundle], line[:name], line[:total][:seconds], line[:total][:time]]}
56
+ end
57
+ else
58
+ exit
59
+ end
60
+ puts "File converted and exported to #{name}\n\n"
61
+ end
62
+
63
+ def save_log options, data, filename
64
+ case
65
+ when options[:json]
66
+ name = @toki.helpers.toki_path + "/#{filename}.json"
67
+ File.write(name, data.to_json)
68
+ when options[:csv]
69
+ name = @toki.helpers.toki_path + "/#{filename}.csv"
70
+ CSV.open(name, "wb") do |csv|
71
+ csv << ['Start', 'Duration (seconds)', 'Duration (time)', 'Sync ID']
72
+ data.each {|line| csv << [line[:start], line[:duration][:seconds], line[:duration][:time], line[:sync_id]]}
73
+ end
74
+ else
75
+ exit
76
+ end
77
+ puts "File converted and exported to #{name}\n\n"
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,122 @@
1
+ # encoding: utf-8
2
+ module TokiCLI
3
+ class Import
4
+
5
+ def initialize toki, view
6
+ @toki_api = toki
7
+ @view = view
8
+ end
9
+
10
+ def restore token, channel_id
11
+ please_quit
12
+ backup_db
13
+ adn_data = get_adn_data token, channel_id
14
+ db = create_db
15
+ create_table db
16
+ lines = decode adn_data
17
+ populate db, lines
18
+ replace
19
+ end
20
+
21
+
22
+ def replace
23
+ if File.exist? @toki_api.helpers.db_path
24
+ puts "\nAre you sure you want to replace the current Toki.app database?\n\nHit SPACE to continue (any other key to cancel).\n\n"
25
+ abort("Canceled.\n\n") unless STDIN.getch == ' '
26
+ FileUtils.mv @toki_api.helpers.db_path, "#{Dir.home}/.Trash/"
27
+ end
28
+ FileUtils.mv @new_db_path, @toki_api.helpers.db_path
29
+ puts "\n\nDone. You may relaunch Toki.app now.\n\n"
30
+ end
31
+
32
+ def populate db, lines
33
+ puts "Populating new database with App.net data...\n\n"
34
+ before = Time.now
35
+ idx = 0
36
+ db.transaction do |db_in_transaction|
37
+ lines.each do |obj|
38
+ insert_data = {}
39
+ insert_data[':id'] = obj[:id]
40
+ insert_data[':bundleIdentifier'] = obj[:bundleIdentifier]
41
+ insert_data[':activeTo'] = obj[:activeTo]
42
+ insert_data[':activeFrom'] = obj[:activeFrom]
43
+ insert_data[':totalSeconds'] = obj[:totalSeconds]
44
+ insert_data[':UUID'] = obj[:uuid]
45
+ insert_data[':synced'] = 1
46
+ insert_data[':availableToSync'] = 1
47
+
48
+ db_in_transaction.prepare("INSERT INTO plain(id, bundleIdentifier, activeTo, activeFrom, totalSeconds, UUID, synced, availableToSync) VALUES(:id, :bundleIdentifier, :activeTo, :activeFrom, :totalSeconds, :UUID, :synced, :availableToSync);") do |insert|
49
+ insert.execute insert_data
50
+ end
51
+
52
+ idx += 1
53
+ print "Processed #{idx} of #{lines.size}\r"
54
+ $stdout.flush
55
+ end
56
+ end
57
+ puts "\n\n\nFinished inserting #{idx} lines in #{Time.now - before}.\n\n"
58
+ end
59
+
60
+ def decode adn_data
61
+ puts "Decoding App.net data...\n\n"
62
+ lines = []
63
+ adn_data.each do |obj|
64
+ adn = obj['annotations'][0]
65
+ lines <<
66
+ {
67
+ type: adn['type'],
68
+ table: adn['value']['c'],
69
+ uuid: adn['value']['d']['UUID'],
70
+ bundleIdentifier: adn['value']['d']['bundleIdentifier'],
71
+ activeTo: adn['value']['d']['activeTo'],
72
+ activeFrom: adn['value']['d']['activeFrom'],
73
+ totalSeconds: adn['value']['d']['totalSeconds'],
74
+ id: adn['value']['d']['id']
75
+ }
76
+ end
77
+ lines
78
+ end
79
+
80
+ def create_table db
81
+ puts "Creating table...\n\n"
82
+ db.execute_batch <<-SQL
83
+ CREATE TABLE KKAppActivity (
84
+ id INTEGER,
85
+ bundleIdentifier VARCHAR(256),
86
+ activeTo INTEGER,
87
+ activeFrom INTEGER,
88
+ totalSeconds INTEGER,
89
+ UUID VARCHAR(256),
90
+ synced INTEGER,
91
+ availableToSync INTEGER
92
+ );
93
+ SQL
94
+ db.reload_schema!
95
+ end
96
+
97
+ def create_db
98
+ puts "\n\nCreating a new SQLite3 database...\n\n"
99
+ @new_db_path = "#{@toki_api.helpers.toki_path}/db_from_adn.sqlite3"
100
+ Amalgalite::Database.new @new_db_path
101
+ end
102
+
103
+ def get_adn_data token, channel_id
104
+ puts "Connecting to App.net...\n\n"
105
+ channels = ADNChannels::GetMessages.new(token)
106
+ channels.get_messages(channel_id)
107
+ end
108
+
109
+ def backup_db
110
+ if File.exist? @toki_api.helpers.db_path
111
+ FileUtils.copy(@toki_api.helpers.db_path, "#{@toki_api.helpers.toki_path}/toki_data.sqlite3.bak")
112
+ puts "Current database has been backed up in #{@toki_api.helpers.toki_path}\n\n"
113
+ end
114
+ end
115
+
116
+ def please_quit
117
+ puts "\n\nYou need to quit Toki.app before restoring data from App.net.\n\nPlease quit Toki.app then hit SPACE to continue (any other key to cancel).\n\n"
118
+ abort("Canceled.\n\n") unless STDIN.getch == ' '
119
+ end
120
+
121
+ end
122
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+ module TokiCLI
3
+ class Scan
4
+
5
+ def initialize toki
6
+ @toki_api = toki
7
+ end
8
+
9
+ def scan params
10
+ bundles = @toki_api.helpers.scan params
11
+ if bundles.empty? || bundles.nil?
12
+ puts "\nError.\n\n"
13
+ else
14
+ puts "\nDone.\n\n"
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -1,3 +1,3 @@
1
1
  module TokiCLI
2
- VERSION = "0.0.9"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -1,70 +1,127 @@
1
1
  # encoding: utf-8
2
2
  module TokiCLI
3
3
  class View
4
- def total_table(list)
4
+
5
+ def total_table(data)
5
6
  table = init_table
6
- table.title = "Your apps monitored by Toki"
7
- puts table_2(list, table)
7
+ clear
8
+ if data['data']['apps']
9
+ table.title = "Your apps monitored by Toki"
10
+ puts apps_3(data, table)
11
+ else
12
+ table.title = "Your app monitored by Toki"
13
+ puts total_3(data, table)
14
+ end
8
15
  puts "\n"
9
16
  end
10
- def day_table(day, list)
17
+
18
+ def app_table(asked, app_data)
11
19
  table = init_table
12
- table.title = "Your apps monitored by Toki on #{day}"
13
- puts table_2(list, table)
20
+ table.style = { :width => 100 }
21
+ name = name_of app_data
22
+ table.title = "Toki time tracking for #{name}"
23
+ table.headings = ['Start', 'Duration', 'Sync ID']
24
+ lines = create_lines app_data
25
+ total = calc_total lines
26
+ format_lines lines
27
+
28
+ #TODO: change this
29
+ display_limit = Time.now - (3600*24*7) # 7 days
30
+ lines.select! {|obj| Time.parse(obj[0]) > display_limit}
31
+
32
+ sort_lines lines
33
+ puts create_table(lines, table)
14
34
  puts "\n"
15
35
  end
16
- def range_table(day1, day2, list)
17
- table = init_table
18
- table.title = "Your apps monitored by Toki between #{day1} and #{day2}"
19
- puts table_2(list, table)
20
- puts "\n"
36
+
37
+ def max_30 text
38
+ text.length >= 30 ? "#{text[0..27]}..." : text
21
39
  end
22
- def hits_table(list)
23
- table = init_table
24
- table.title = "Your top apps monitored by Toki"
25
- puts table2_index(list, table)
26
- puts "\n"
40
+
41
+ def force_name name
42
+ name.nil? ? ' ' : name
27
43
  end
28
- def app_table(asked, app_data)
29
- table = init_table
30
- table.style = { :width => 100 }
31
- table.title = "Toki time tracking for '#{asked}' => #{app_data.first[1][:name]}"
32
- table.headings = ['From', 'To', 'Duration', 'Sync id']
33
- @index = 0
34
- @length = app_data.length - 1
35
- @total = app_data.select {|k,v| k == 'total'}
36
- app_data.delete('total')
37
- data = app_data.to_a
38
- data.sort_by! {|k,v| v[:raw_from] }
39
- data.each do |id, log|
40
- @index += 1
41
- table << ["#{log[:from]}", "#{log[:to]}", "#{log[:duration]}", "#{id}"]
42
- table << :separator unless @index == @length
44
+
45
+ def humanized_date epoch
46
+ human = seconds_to_time epoch
47
+ "#{human[:hours]}h #{human[:minutes]}m #{human[:seconds]}s"
48
+ end
49
+
50
+ def seconds_to_time epoch
51
+ hours = epoch / 3600
52
+ minutes = (epoch / 60 - hours * 60)
53
+ seconds = (epoch - (minutes * 60 + hours * 3600))
54
+ {hours: hours, minutes: minutes, seconds: seconds}
55
+ end
56
+
57
+ def readable_time time
58
+ "#{'%.2d' % time['hours']}h #{'%.2d' % time['minutes']}m #{'%.2d' % time['seconds']}s"
59
+ end
60
+
61
+ def clear
62
+ puts "\e[H\e[2J"
63
+ end
64
+
65
+ private
66
+
67
+ def create_table lines, table
68
+ index = 0
69
+ length = lines.length - 1
70
+ lines.each do |obj|
71
+ table << obj
72
+ table << :separator unless index == length
73
+ index += 1
43
74
  end
44
75
  table << :separator
45
- table << [{ :value => "Total: #{@total['total']}", :colspan => 4, :alignment => :center }]
46
- puts table
47
- puts "\n"
76
+ table << [{ :value => "Total: #{humanized_date(total)}", :colspan => 3, :alignment => :center }]
77
+ table
48
78
  end
49
79
 
50
- private
80
+ def sort_lines lines
81
+ lines.sort_by! {|obj| obj[0]}
82
+ end
83
+
84
+ def format_lines lines
85
+ lines.map! {|obj| [obj[0], obj[1], obj[2]]}
86
+ end
87
+
88
+ def calc_total lines
89
+ total = 0
90
+ lines.each {|v| total += v[3]}
91
+ total
92
+ end
93
+
94
+ def create_lines app_data
95
+ lines = []
96
+ app_data['data']['log'].each {|k,v| lines << [v['start'], readable_time(v['duration']['time']), k, v['duration']['seconds']]}
97
+ lines
98
+ end
99
+
100
+ def name_of app_data
101
+ if app_data['data']['name']
102
+ app_data['data']['name']
103
+ else
104
+ app_data['data']['bundle']
105
+ end
106
+ end
51
107
 
52
108
  def init_table
53
109
  Terminal::Table.new do |t|
54
- t.style = { :width => 75 }
110
+ t.style = { :width => 100 }
55
111
  end
56
112
  end
57
- def table_2(list, table)
58
- list.each do |k,v|
59
- table << ["#{k}", "#{v}"]
113
+
114
+ def apps_3 resp, table
115
+ resp['data']['apps'].each do |obj|
116
+ table << [max_30(obj['bundle']), max_30(force_name(obj['name'])), readable_time(obj['total']['time'])]
60
117
  end
61
118
  table
62
119
  end
63
- def table2_index(list, table)
64
- list.each.with_index(1) do |obj,index|
65
- table << ["#{index}", "#{obj[0]}", "#{obj[1]}"]
66
- end
120
+
121
+ def total_3 resp, table
122
+ table << [max_30(resp['data']['bundle']), max_30(force_name(resp['data']['name'])), readable_time(resp['data']['total']['time'])]
67
123
  table
68
124
  end
125
+
69
126
  end
70
127
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: TokiCLI
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Dejonckheere
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-29 00:00:00.000000000 Z
11
+ date: 2014-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 2.2.8
75
+ version: '2.2'
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 2.2.8
82
+ version: '2.2'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: bundler
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -126,12 +126,16 @@ files:
126
126
  - Rakefile
127
127
  - TokiCLI.gemspec
128
128
  - bin/toki
129
+ - lib/API/dbapi.rb
130
+ - lib/API/helpers.rb
129
131
  - lib/TokiCLI.rb
130
132
  - lib/TokiCLI/app.rb
131
133
  - lib/TokiCLI/authorize.rb
134
+ - lib/TokiCLI/export.rb
132
135
  - lib/TokiCLI/get_channels.rb
133
136
  - lib/TokiCLI/get_messages.rb
134
- - lib/TokiCLI/module.rb
137
+ - lib/TokiCLI/import.rb
138
+ - lib/TokiCLI/scan.rb
135
139
  - lib/TokiCLI/search_messages.rb
136
140
  - lib/TokiCLI/status.rb
137
141
  - lib/TokiCLI/version.rb
@@ -148,7 +152,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
148
152
  requirements:
149
153
  - - ">="
150
154
  - !ruby/object:Gem::Version
151
- version: 1.9.3
155
+ version: 2.0.0
152
156
  required_rubygems_version: !ruby/object:Gem::Requirement
153
157
  requirements:
154
158
  - - ">="
@@ -161,4 +165,3 @@ signing_key:
161
165
  specification_version: 4
162
166
  summary: Toki.app command-line client
163
167
  test_files: []
164
- has_rdoc: