TokiCLI 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.coveralls.yml +1 -0
- data/.gitignore +9 -17
- data/.rspec +3 -0
- data/.travis.yml +3 -0
- data/CHANGELOG.md +4 -0
- data/README.md +99 -163
- data/Rakefile +5 -0
- data/TokiCLI.gemspec +5 -4
- data/bin/toki +2 -2
- data/lib/API/helpers.rb +27 -170
- data/lib/API/toki_api.rb +227 -0
- data/lib/API/toki_db.rb +67 -0
- data/lib/TokiCLI.rb +270 -5
- data/lib/TokiCLI/adnimport.rb +202 -0
- data/lib/TokiCLI/fileops.rb +187 -0
- data/lib/TokiCLI/status.rb +49 -37
- data/lib/TokiCLI/version.rb +1 -1
- data/lib/TokiCLI/view.rb +133 -86
- data/lib/TokiServer/.bowerrc +3 -0
- data/lib/TokiServer/.gitignore +2 -0
- data/lib/TokiServer/Gemfile +1 -0
- data/lib/TokiServer/bower.json +0 -0
- data/lib/TokiServer/bower_components/fastclick/.bower.json +4 -4
- data/lib/TokiServer/bower_components/fastclick/bower.json +1 -1
- data/lib/TokiServer/bower_components/fastclick/lib/fastclick.js +33 -2
- data/lib/TokiServer/bower_components/foundation/.bower.json +5 -4
- data/lib/TokiServer/bower_components/foundation/bower.json +2 -1
- data/lib/TokiServer/bower_components/foundation/css/foundation.css +2173 -922
- data/lib/TokiServer/bower_components/foundation/css/foundation.css.map +7 -0
- data/lib/TokiServer/bower_components/foundation/css/normalize.css +53 -16
- data/lib/TokiServer/bower_components/foundation/css/normalize.css.map +7 -0
- data/lib/TokiServer/bower_components/foundation/js/foundation.js +782 -542
- data/lib/TokiServer/bower_components/foundation/js/foundation.min.js +4 -3
- data/lib/TokiServer/bower_components/foundation/js/foundation/foundation.abide.js +45 -31
- data/lib/TokiServer/bower_components/foundation/js/foundation/foundation.accordion.js +12 -6
- data/lib/TokiServer/bower_components/foundation/js/foundation/foundation.alert.js +5 -5
- data/lib/TokiServer/bower_components/foundation/js/foundation/foundation.clearing.js +34 -10
- data/lib/TokiServer/bower_components/foundation/js/foundation/foundation.dropdown.js +83 -29
- data/lib/TokiServer/bower_components/foundation/js/foundation/foundation.equalizer.js +3 -3
- data/lib/TokiServer/bower_components/foundation/js/foundation/foundation.interchange.js +25 -12
- data/lib/TokiServer/bower_components/foundation/js/foundation/foundation.joyride.js +112 -40
- data/lib/TokiServer/bower_components/foundation/js/foundation/foundation.js +19 -5
- data/lib/TokiServer/bower_components/foundation/js/foundation/foundation.magellan.js +22 -11
- data/lib/TokiServer/bower_components/foundation/js/foundation/foundation.offcanvas.js +52 -8
- data/lib/TokiServer/bower_components/foundation/js/foundation/foundation.orbit.js +133 -271
- data/lib/TokiServer/bower_components/foundation/js/foundation/foundation.reveal.js +27 -20
- data/lib/TokiServer/bower_components/foundation/js/foundation/foundation.slider.js +73 -33
- data/lib/TokiServer/bower_components/foundation/js/foundation/foundation.tab.js +88 -31
- data/lib/TokiServer/bower_components/foundation/js/foundation/foundation.tooltip.js +7 -5
- data/lib/TokiServer/bower_components/foundation/js/foundation/foundation.topbar.js +44 -24
- data/lib/TokiServer/bower_components/foundation/js/vendor/fastclick.js +2 -2
- data/lib/TokiServer/bower_components/foundation/js/vendor/modernizr.js +2 -2
- data/lib/TokiServer/bower_components/foundation/scss/foundation.scss +38 -38
- data/lib/TokiServer/bower_components/foundation/scss/foundation/_functions.scss +3 -3
- data/lib/TokiServer/bower_components/foundation/scss/foundation/_settings.scss +417 -271
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_accordion.scss +110 -6
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_alert-boxes.scss +2 -2
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_block-grid.scss +2 -2
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_breadcrumbs.scss +8 -3
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_button-groups.scss +99 -9
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_buttons.scss +66 -28
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_clearing.scss +5 -5
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_dropdown-buttons.scss +4 -4
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_dropdown.scss +48 -35
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_forms.scss +104 -32
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_global.scss +48 -30
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_grid.scss +19 -4
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_icon-bar.scss +293 -0
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_joyride.scss +11 -9
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_keystrokes.scss +4 -4
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_labels.scss +4 -2
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_magellan.scss +1 -1
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_offcanvas.scss +193 -35
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_orbit.scss +92 -147
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_pagination.scss +22 -10
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_panels.scss +10 -7
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_pricing-tables.scss +11 -11
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_progress-bars.scss +2 -2
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_range-slider.scss +29 -9
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_reveal.scss +60 -56
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_side-nav.scss +3 -2
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_split-buttons.scss +2 -2
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_sub-nav.scss +2 -2
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_switches.scss +226 -0
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_tables.scss +13 -7
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_tabs.scss +22 -8
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_thumbs.scss +2 -4
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_toolbar.scss +70 -0
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_tooltips.scss +9 -7
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_top-bar.scss +77 -44
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_type.scss +21 -9
- data/lib/TokiServer/bower_components/modernizr/.bower.json +4 -4
- data/lib/TokiServer/bower_components/modernizr/feature-detects/workers-blobworkers.js +2 -2
- data/lib/TokiServer/bower_components/modernizr/grunt.js +1 -1
- data/lib/TokiServer/bower_components/modernizr/modernizr.js +2 -2
- data/lib/TokiServer/config.rb +0 -0
- data/lib/TokiServer/humans.txt +0 -0
- data/lib/TokiServer/{itunesicon.rb → itunesicons.rb} +25 -23
- data/lib/TokiServer/js/app.js +0 -0
- data/lib/TokiServer/public/stylesheets/app.css +2636 -1610
- data/lib/TokiServer/robots.txt +0 -0
- data/lib/TokiServer/scss/_settings.scss +0 -0
- data/lib/TokiServer/scss/app.scss +7 -1
- data/lib/TokiServer/tokiserver.rb +239 -244
- data/lib/TokiServer/views/activity.erb +42 -0
- data/lib/TokiServer/views/apps_total.erb +8 -2
- data/lib/TokiServer/views/error.erb +13 -4
- data/lib/TokiServer/views/index.erb +36 -27
- data/lib/TokiServer/views/logs_total.erb +34 -0
- data/spec/TokiCLI_spec.rb +354 -0
- data/spec/mock/mock.sqlite3 +0 -0
- data/spec/spec_helper.rb +26 -0
- metadata +78 -23
- data/lib/API/dbapi.rb +0 -488
- data/lib/TokiCLI/app.rb +0 -389
- data/lib/TokiCLI/authorize.rb +0 -77
- data/lib/TokiCLI/export.rb +0 -81
- data/lib/TokiCLI/get_channels.rb +0 -22
- data/lib/TokiCLI/get_messages.rb +0 -32
- data/lib/TokiCLI/import.rb +0 -122
- data/lib/TokiCLI/scan.rb +0 -19
- data/lib/TokiCLI/search_messages.rb +0 -23
- data/lib/TokiServer/README.md +0 -37
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_reveal-new.scss +0 -0
- data/lib/TokiServer/bower_components/foundation/scss/foundation/components/_switch.scss +0 -294
- data/lib/TokiServer/views/name_log.erb +0 -50
- data/lib/TokiServer/views/name_split.erb +0 -37
- data/lib/TokiServer/views/name_total.erb +0 -34
@@ -0,0 +1,187 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module TokiCLI
|
3
|
+
class FileOps
|
4
|
+
|
5
|
+
require 'fileutils'
|
6
|
+
require 'CFPropertyList'
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
attr_accessor :home_path, :toki_path, :db_path, :db_file, :bundles_file, :bundles, :config_file, :config_path, :config, :data_path, :files_path, :user_file, :log_path
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@home_path = Dir.home
|
13
|
+
@toki_path = "#{@home_path}/.TokiCLI"
|
14
|
+
@data_path = "#{@toki_path}/data"
|
15
|
+
@config_path = "#{@toki_path}/config"
|
16
|
+
@files_path = "#{@toki_path}/files"
|
17
|
+
@backup_path = "#{@toki_path}/backup"
|
18
|
+
@log_path = "#{@toki_path}/log"
|
19
|
+
@db_path = "#{@home_path}/Library/Containers/us.kkob.Toki/Data/Documents"
|
20
|
+
@db_file = "#{@db_path}/toki_data.sqlite3"
|
21
|
+
@bundles_file = "#{@files_path}/bundles.json"
|
22
|
+
@config_file = "#{@config_path}/config.yml"
|
23
|
+
@user_file = "#{@data_path}/user.json"
|
24
|
+
make_toki_dirs()
|
25
|
+
@bundles = load_bundles()
|
26
|
+
@config = create_config()
|
27
|
+
end
|
28
|
+
|
29
|
+
def backup_db
|
30
|
+
FileUtils.copy(@db_file, "#{@backup_path}/toki_data.sqlite3.bak")
|
31
|
+
end
|
32
|
+
|
33
|
+
def load_bundles
|
34
|
+
if File.exist?(@bundles_file)
|
35
|
+
JSON.parse(File.read(@bundles_file))
|
36
|
+
else
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def save_bundles
|
42
|
+
@bundles = get_bundle_ids()
|
43
|
+
File.write(@bundles_file, @bundles.to_json)
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_bundle_from_name(name)
|
47
|
+
app_name = name.map {|n| n.downcase}.join(' ')
|
48
|
+
candidates = []
|
49
|
+
@bundles.each do |bundle_id, bundle_name|
|
50
|
+
if bundle_name.downcase =~ /#{app_name}/
|
51
|
+
candidates << bundle_id
|
52
|
+
end
|
53
|
+
end
|
54
|
+
return candidates
|
55
|
+
end
|
56
|
+
|
57
|
+
def export(toki, options, title = nil)
|
58
|
+
response = JSON.parse(toki.response)
|
59
|
+
type = response['meta']['request']['type']
|
60
|
+
prefix = response['meta']['request']['processed_at'][0..9]
|
61
|
+
path = if title.nil?
|
62
|
+
"#{@data_path}/#{prefix}_#{type}"
|
63
|
+
else
|
64
|
+
"#{@data_path}/#{prefix}_#{type}_#{title.tr_s(' ', '-')}"
|
65
|
+
end
|
66
|
+
if options[:json]
|
67
|
+
file = "#{path}.json"
|
68
|
+
File.write(file, toki.response)
|
69
|
+
elsif options[:csv]
|
70
|
+
file = "#{path}.csv"
|
71
|
+
if type == 'apps'
|
72
|
+
export_apps_csv(response, file)
|
73
|
+
elsif type == 'log'
|
74
|
+
export_log_csv(response, file)
|
75
|
+
end
|
76
|
+
else
|
77
|
+
abort(Status.wtf)
|
78
|
+
end
|
79
|
+
puts Status.file_saved(file)
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def export_apps_csv(response, file)
|
85
|
+
CSV.open(file, "wb") do |csv|
|
86
|
+
csv << ['Bundle', 'Name', 'Total', 'Hours', 'Minutes', 'Seconds']
|
87
|
+
response['data'].each do |line|
|
88
|
+
csv << [line['bundle'], line['name'], line['total']['seconds'], line['total']['time']['hours'], line['total']['time']['minutes'], line['total']['time']['seconds']]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def export_log_csv(response, file)
|
94
|
+
CSV.open(file, "wb") do |csv|
|
95
|
+
csv << ['Start', 'Duration (seconds)', 'Minutes', 'Seconds', 'Sync ID']
|
96
|
+
response['data'].each {|line| csv << [line[1]['start'], line[1]['duration']['seconds'], line[1]['duration']['time']['minutes'], line[1]['duration']['time']['seconds'], line[0]]}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def make_toki_dirs
|
101
|
+
%w{backup data files config log}.each do |dir|
|
102
|
+
path = "#{@toki_path}/#{dir}"
|
103
|
+
FileUtils.mkdir_p(path) unless Dir.exist?(path)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def create_config
|
108
|
+
return YAML.load(File.read(@config_file)) if File.exist?(@config_file)
|
109
|
+
settings = {
|
110
|
+
'table' => {
|
111
|
+
'width' => 90
|
112
|
+
}
|
113
|
+
}
|
114
|
+
File.write(@config_file, settings.to_yaml)
|
115
|
+
return YAML.load(File.read(@config_file))
|
116
|
+
end
|
117
|
+
|
118
|
+
# Scan for names from bundle ids
|
119
|
+
def get_bundle_ids
|
120
|
+
@names = {}
|
121
|
+
get_bundles(get_plists("/Applications/*/Contents/*"))
|
122
|
+
get_bundles(get_plists("/Applications/Utilities/*/Contents/*"))
|
123
|
+
get_bundles(get_plists("#{@home_path}/Applications/*/Contents/*"))
|
124
|
+
specials = {
|
125
|
+
'com.evernote.EvernoteHelper' => 'Evernote Helper',
|
126
|
+
'com.apple.finder' => 'Finder',
|
127
|
+
'com.apple.ReportPanic' => 'Kernel Panic',
|
128
|
+
'com.apple.coreservices.uiagent' => 'CoreServices UIAgent',
|
129
|
+
'com.apple.installer' => 'Apple Installer',
|
130
|
+
'com.apple.frameworks.diskimages.diuiagent' => 'Apple Disk Images Agent',
|
131
|
+
'com.mediaatelier.CheatSheet' => 'Cheat Sheet',
|
132
|
+
'com.vyprvpn.authorization' => 'VyprVPN',
|
133
|
+
'com.apple.WebKit.WebContent' => 'Safari module',
|
134
|
+
'com.apple.ProblemReporter' => 'Apple Problem Reporter',
|
135
|
+
'org.andymatuschak.sparkle.finish-installation' => 'Sparkle Install',
|
136
|
+
'com.noodlesoft.HazelHelper' => 'Hazel Helper',
|
137
|
+
'de.appsolute.MAMP' => 'MAMP',
|
138
|
+
'com.apple.KeyboardSetupAssistant' => 'Apple Keyboard Setup Assistant',
|
139
|
+
'com.apple.NetAuthAgent' => 'Apple Net Auth Agent',
|
140
|
+
'com.adobe.acc.AdobeCreativeCloud' => 'Adobe Creative Cloud',
|
141
|
+
'com.apple.iphonesimulator' => 'Apple iPhone Simulator',
|
142
|
+
'com.macromates.TextMate.preview' => 'TextMate',
|
143
|
+
'com.alfredapp.Alfred' => 'Alfred',
|
144
|
+
'com.runningwithcrayons.Alfred-Preferences' => 'Alfred Preferences',
|
145
|
+
'com.apple.WebKit.PluginProcess' => 'Safari Plugin',
|
146
|
+
'com.apple.ScreenSharing' => 'Apple Screen Sharing',
|
147
|
+
'org.virtualbox.app.VirtualBoxVM' => 'VirtualBox',
|
148
|
+
'2BUA8C4S2C.com.agilebits.onepassword-osx-helper' => '1Password Helper',
|
149
|
+
'com.apple.AirPlayUIAgent' => 'AirPlayUIAgent',
|
150
|
+
'com.apple.ScreenSaver.Engine' => 'ScreenSaver',
|
151
|
+
'com.adobe.PDApp' => 'Adobe Application Manager',
|
152
|
+
'com.screentime.flash.builder' => 'Screentime for Flash',
|
153
|
+
'com.apple.systemuiserver' => 'SystemUIServer',
|
154
|
+
'org.mozilla.plugincontainer' => 'Mozilla Plugin-container',
|
155
|
+
'com.adobe.ACCC.Uninstaller' => 'Adobe Creative Cloud Uninstaller',
|
156
|
+
'com.smileonmymac.textexpander' => 'TextExpander',
|
157
|
+
'org.pqrs.Karabiner-AXNotifier' => 'Karabiner Notifier',
|
158
|
+
'com.apple.DiskImageMounter' => 'Apple Disk Image Mounter'
|
159
|
+
}
|
160
|
+
specials.each { |k, v| @names[k] = v }
|
161
|
+
return @names
|
162
|
+
end
|
163
|
+
|
164
|
+
def get_plists path
|
165
|
+
Dir.glob(path).select {|f| (File.split f).last == 'Info.plist'}
|
166
|
+
end
|
167
|
+
|
168
|
+
def get_bundles plists
|
169
|
+
plists.each do |obj|
|
170
|
+
puts Status.analysing(obj)
|
171
|
+
begin
|
172
|
+
pl = CFPropertyList::List.new(:file => obj)
|
173
|
+
rescue CFFormatError, NoMethodError
|
174
|
+
puts Status.no_plist
|
175
|
+
next
|
176
|
+
end
|
177
|
+
data = CFPropertyList.native_types(pl.value)
|
178
|
+
name = data['CFBundleName'] || data['CFBundleExecutable']
|
179
|
+
next if name.nil?
|
180
|
+
bundle_id = data['CFBundleIdentifier']
|
181
|
+
next if bundle_id.nil? || bundle_id.empty?
|
182
|
+
@names[bundle_id] = name
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
end
|
data/lib/TokiCLI/status.rb
CHANGED
@@ -1,41 +1,53 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module TokiCLI
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
3
|
+
|
4
|
+
module Status
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
|
8
|
+
def canceled
|
9
|
+
"\nCanceled.\n\n"
|
10
|
+
end
|
11
|
+
|
12
|
+
def version(version)
|
13
|
+
"\n-- TokiCLI --\n\nVersion:\t#{version}\nUrl:\t\thttp://github.com/ericdke/TokiCLI\n\n"
|
14
|
+
end
|
15
|
+
|
16
|
+
def wtf
|
17
|
+
"\nAn error occurred! Goodbye, and thanks for all the fish.\n\n"
|
18
|
+
end
|
19
|
+
|
20
|
+
def no_plist
|
21
|
+
"Unable to read the file, skipping...\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
def no_data
|
25
|
+
"\nNo data for this request.\n\n"
|
26
|
+
end
|
27
|
+
|
28
|
+
def analysing(obj)
|
29
|
+
"Analyzing #{obj} ...\n"
|
30
|
+
end
|
31
|
+
|
32
|
+
def scanning
|
33
|
+
"\nScanning applications bundles to find their names.\n\n"
|
34
|
+
end
|
35
|
+
|
36
|
+
def file_saved(path)
|
37
|
+
"\nFile saved in #{path}\n\n"
|
38
|
+
end
|
39
|
+
|
40
|
+
def next_launch_with_names
|
41
|
+
"Starting with next launch, TokiCLI will display apps names. Run `toki scan` again to update the apps list.\n\n"
|
42
|
+
end
|
43
|
+
|
44
|
+
def please_scan
|
45
|
+
"\nPlease run `toki scan` to populate/refresh the applications names database.\n\n"
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
extend ClassMethods # This is a way to avoid having to declare self.xxx for each def
|
40
51
|
end
|
52
|
+
|
41
53
|
end
|
data/lib/TokiCLI/version.rb
CHANGED
data/lib/TokiCLI/view.rb
CHANGED
@@ -1,132 +1,179 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
|
2
3
|
module TokiCLI
|
4
|
+
|
3
5
|
class View
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
if
|
9
|
-
if
|
10
|
-
table.title = "Your apps monitored by Toki: #{data['data']['date']}"
|
11
|
-
else
|
12
|
-
table.title = "Your apps monitored by Toki"
|
13
|
-
end
|
14
|
-
puts apps_3(data, table)
|
7
|
+
require 'terminal-table'
|
8
|
+
|
9
|
+
def initialize settings = {}
|
10
|
+
@settings = if settings.empty?
|
11
|
+
{"table"=>{"width"=>90}} # force default if no initialization
|
15
12
|
else
|
16
|
-
|
17
|
-
puts total_3(data, table)
|
13
|
+
settings
|
18
14
|
end
|
19
|
-
puts "\n"
|
20
|
-
end
|
21
|
-
|
22
|
-
def app_table(asked, app_data)
|
23
|
-
table = init_table
|
24
|
-
table.style = { :width => 100 }
|
25
|
-
name = name_of(app_data)
|
26
|
-
table.title = "Toki time tracking for #{name}"
|
27
|
-
table.headings = ['Start', 'Duration', 'Sync ID']
|
28
|
-
lines = create_lines app_data
|
29
|
-
total = calc_total lines
|
30
|
-
format_lines lines
|
31
|
-
|
32
|
-
#TODO: change this
|
33
|
-
display_limit = Time.now - (3600*24*7) # 7 days
|
34
|
-
lines.select! {|obj| Time.parse(obj[0]) > display_limit}
|
35
|
-
|
36
|
-
sort_lines lines
|
37
|
-
|
38
|
-
puts create_table(lines, table, total)
|
39
|
-
puts "\n"
|
40
15
|
end
|
41
16
|
|
42
|
-
def
|
43
|
-
|
17
|
+
def version
|
18
|
+
table = init_table("TokiCLI for Toki.app")
|
19
|
+
table << ['Version', VERSION]
|
20
|
+
table << :separator
|
21
|
+
table << ['Infos', 'http://github.com/ericdke/TokiCLI']
|
22
|
+
puts "\n#{table}\n"
|
44
23
|
end
|
45
24
|
|
46
|
-
def
|
47
|
-
|
25
|
+
def apps_total(api_response, title = "Your apps monitored by Toki")
|
26
|
+
table, apps = make_apps_table(api_response, title)
|
27
|
+
puts "\n"
|
28
|
+
display, total = populate_apps_table(table, apps)
|
29
|
+
display << :separator
|
30
|
+
display << insert_total_line(total)
|
31
|
+
puts "\e[H\e[2J"
|
32
|
+
puts display
|
48
33
|
end
|
49
34
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
35
|
+
def apps(api_response, title = "Your apps monitored by Toki")
|
36
|
+
table, apps = make_apps_table(api_response, title)
|
37
|
+
puts "\n"
|
38
|
+
display, _ = populate_apps_table(table, apps)
|
39
|
+
puts "\e[H\e[2J"
|
40
|
+
puts display
|
53
41
|
end
|
54
42
|
|
55
|
-
def
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
43
|
+
def log(api_response, title = "Your app monitored by Toki")
|
44
|
+
display, _ = make_log_table(api_response, title)
|
45
|
+
puts "\nRendering the view, please wait.\n\n"
|
46
|
+
lines = display.render
|
47
|
+
puts "\e[H\e[2J"
|
48
|
+
puts lines
|
60
49
|
end
|
61
50
|
|
62
|
-
def
|
63
|
-
|
51
|
+
def log_total(api_response, title = "Your app monitored by Toki")
|
52
|
+
display, total = make_log_table(api_response, title)
|
53
|
+
display << :separator
|
54
|
+
display << insert_total_line(total)
|
55
|
+
puts "\nRendering the view, please wait.\n\n"
|
56
|
+
lines = display.render
|
57
|
+
puts "\e[H\e[2J"
|
58
|
+
puts lines
|
64
59
|
end
|
65
60
|
|
66
|
-
def
|
67
|
-
|
61
|
+
def log_activity(api_response)
|
62
|
+
log = JSON.parse(api_response)['data']
|
63
|
+
table = init_table()
|
64
|
+
table.headings = ['Bundle', 'Start', 'Duration', 'Sync ID']
|
65
|
+
lines = make_log_lines(log)
|
66
|
+
display, _ = populate_log_table(lines, table, true)
|
67
|
+
puts display
|
68
68
|
end
|
69
69
|
|
70
70
|
private
|
71
71
|
|
72
|
-
def
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
table << obj
|
77
|
-
table << :separator unless index == length
|
78
|
-
index += 1
|
72
|
+
def init_table(title = 'TokiCLI')
|
73
|
+
Terminal::Table.new do |t|
|
74
|
+
t.style = { :width => @settings['table']['width'] }
|
75
|
+
t.title = title
|
79
76
|
end
|
80
|
-
table << :separator
|
81
|
-
table << [{ :value => "Total: #{humanized_date(total)}", :colspan => 3, :alignment => :center }]
|
82
|
-
table
|
83
77
|
end
|
84
78
|
|
85
|
-
def
|
86
|
-
|
79
|
+
def make_log_table(api_response, title)
|
80
|
+
log = JSON.parse(api_response)['data']
|
81
|
+
table = init_table(title)
|
82
|
+
table.headings = ['Start', 'Duration', 'Sync ID']
|
83
|
+
lines = make_log_lines(log)
|
84
|
+
return populate_log_table(lines, table)
|
87
85
|
end
|
88
86
|
|
89
|
-
def
|
90
|
-
|
87
|
+
def make_apps_table(api_response, title)
|
88
|
+
apps = JSON.parse(api_response)['data']
|
89
|
+
table = init_table(title)
|
90
|
+
table.headings = ['Bundle ID', 'Name', 'Total']
|
91
|
+
return table, apps
|
91
92
|
end
|
92
93
|
|
93
|
-
def
|
94
|
-
total
|
95
|
-
lines.each {|v| total += v[3]}
|
96
|
-
total
|
94
|
+
def insert_total_line(total, text = 'Total')
|
95
|
+
[{ :value => "#{text}: #{readable_time(sec_to_time(total))}", :colspan => 3, :alignment => :center }]
|
97
96
|
end
|
98
97
|
|
99
|
-
def
|
100
|
-
|
101
|
-
app_data['data']['log'].each {|k,v| lines << [v['start'], readable_time(v['duration']['time']), k, v['duration']['seconds']]}
|
102
|
-
lines
|
98
|
+
def make_log_lines(log)
|
99
|
+
log.map { |k, v| [v['start'], readable_time_log(v['duration']['time']), k, v['duration']['seconds'], v['bundle']] }
|
103
100
|
end
|
104
101
|
|
105
|
-
def
|
106
|
-
|
107
|
-
|
102
|
+
def populate_log_table(lines, table, with_bundle = false)
|
103
|
+
day = lines[0][0][0..9]
|
104
|
+
if with_bundle == false
|
105
|
+
table << [{ :value => "#{day}", :colspan => 3, :alignment => :center }]
|
108
106
|
else
|
109
|
-
|
107
|
+
table << [{ :value => "#{day}", :colspan => 4, :alignment => :center }]
|
108
|
+
table << :separator
|
110
109
|
end
|
110
|
+
total = 0
|
111
|
+
lines.each.with_index(1) do |line, index|
|
112
|
+
new_day = line[0][0..9]
|
113
|
+
unless day == new_day
|
114
|
+
table << :separator
|
115
|
+
if with_bundle == false
|
116
|
+
table << [{ :value => "#{new_day}", :colspan => 3, :alignment => :center }]
|
117
|
+
else
|
118
|
+
table << [{ :value => "#{new_day}", :colspan => 4, :alignment => :center }]
|
119
|
+
end
|
120
|
+
table << :separator
|
121
|
+
end
|
122
|
+
if with_bundle == false
|
123
|
+
table << [line[0][10..18], line[1], line[2]]
|
124
|
+
else
|
125
|
+
table << [line[4], line[0][10..18], line[1], line[2]]
|
126
|
+
# table << :separator unless index == lines.size
|
127
|
+
end
|
128
|
+
day = new_day
|
129
|
+
total += line[3]
|
130
|
+
end
|
131
|
+
return table, total
|
111
132
|
end
|
112
133
|
|
113
|
-
def
|
114
|
-
|
115
|
-
|
134
|
+
def populate_apps_table(table, apps)
|
135
|
+
total = 0
|
136
|
+
apps.each do |app|
|
137
|
+
total += app['total']['seconds']
|
138
|
+
if app['name']
|
139
|
+
table << app_row_with_name(app)
|
140
|
+
else
|
141
|
+
table << app_row(app)
|
142
|
+
end
|
116
143
|
end
|
144
|
+
return table, total
|
117
145
|
end
|
118
146
|
|
119
|
-
def
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
147
|
+
def app_row_with_name(obj)
|
148
|
+
max = @settings['table']['width'] / 3
|
149
|
+
[width(max + 5, obj['bundle']), width(max - 5, obj['name']), readable_time(obj['total']['time'])]
|
150
|
+
end
|
151
|
+
|
152
|
+
def app_row(obj)
|
153
|
+
max = @settings['table']['width'] / 2
|
154
|
+
[width(max, obj['bundle']), '(unknown)', readable_time(obj['total']['time'])]
|
155
|
+
end
|
156
|
+
|
157
|
+
def width(width, text)
|
158
|
+
boundary = width - 3
|
159
|
+
text.length >= width ? "#{text[0..boundary]}..." : text
|
124
160
|
end
|
125
161
|
|
126
|
-
def
|
127
|
-
|
128
|
-
|
162
|
+
def readable_time(obj)
|
163
|
+
"#{obj['hours']}h #{'%.2d' % obj['minutes']}m #{'%.2d' % obj['seconds']}s"
|
164
|
+
end
|
165
|
+
|
166
|
+
def readable_time_log(obj)
|
167
|
+
"#{'%.2d' % obj['minutes']}m #{'%.2d' % obj['seconds']}s"
|
168
|
+
end
|
169
|
+
|
170
|
+
def sec_to_time(secs)
|
171
|
+
hours = secs / 3600
|
172
|
+
minutes = (secs / 60 - hours * 60)
|
173
|
+
seconds = (secs - (minutes * 60 + hours * 3600))
|
174
|
+
{'hours' => hours, 'minutes' => minutes, 'seconds' => seconds}
|
129
175
|
end
|
130
176
|
|
131
177
|
end
|
178
|
+
|
132
179
|
end
|