toggl-worktime 0.1.8 → 0.4.0
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 +4 -4
- data/.rubocop.yml +4 -0
- data/CHANGELOG.md +67 -0
- data/README.md +82 -0
- data/exe/toggl-worktime +43 -21
- data/lib/toggl/worktime.rb +4 -0
- data/lib/toggl/worktime/calendar.rb +93 -0
- data/lib/toggl/worktime/config.rb +49 -0
- data/lib/toggl/worktime/driver.rb +41 -15
- data/lib/toggl/worktime/merger.rb +24 -6
- data/lib/toggl/worktime/time.rb +2 -2
- data/lib/toggl/worktime/version.rb +1 -1
- data/toggl-worktime.gemspec +6 -6
- metadata +40 -24
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a50c3becb0b4a9536811b9c003e3cbc611a5dcdacf20169d3f8ed09bd8955003
|
|
4
|
+
data.tar.gz: 80bfb02dc2272c04f8678835a6c5424caf599a5052e6bbb3a6f3d141458d5699
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 635b3b61cde0e75cc19527a65f04c224f23e3c41866c3921b8e6f3dd59268013fab775ffa60ff6d780422a27ee6578cce2abbaac14cb1c27215e38c20a2fa957
|
|
7
|
+
data.tar.gz: c4938047c7dd2d4989f815cde8cb599a6a3c97e16001ee9d39a3edfa8249cbf9caa2f3ce4e5bd0fb72b0de668ebc2224653e2f82bb6dfe20e9372ea7b40aac5c
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
## [v0.3.2](https://github.com/limitusus/toggl-worktime/tree/v0.3.2) (2018-09-26)
|
|
4
|
+
[Full Changelog](https://github.com/limitusus/toggl-worktime/compare/v0.3.1...v0.3.2)
|
|
5
|
+
|
|
6
|
+
**Merged pull requests:**
|
|
7
|
+
|
|
8
|
+
- Deal with empty time slot [\#7](https://github.com/limitusus/toggl-worktime/pull/7) ([limitusus](https://github.com/limitusus))
|
|
9
|
+
|
|
10
|
+
## [v0.3.1](https://github.com/limitusus/toggl-worktime/tree/v0.3.1) (2018-09-26)
|
|
11
|
+
[Full Changelog](https://github.com/limitusus/toggl-worktime/compare/v0.3.0...v0.3.1)
|
|
12
|
+
|
|
13
|
+
**Merged pull requests:**
|
|
14
|
+
|
|
15
|
+
- Bugfix/interval [\#6](https://github.com/limitusus/toggl-worktime/pull/6) ([limitusus](https://github.com/limitusus))
|
|
16
|
+
|
|
17
|
+
## [v0.3.0](https://github.com/limitusus/toggl-worktime/tree/v0.3.0) (2018-08-01)
|
|
18
|
+
[Full Changelog](https://github.com/limitusus/toggl-worktime/compare/v0.2.0...v0.3.0)
|
|
19
|
+
|
|
20
|
+
**Closed issues:**
|
|
21
|
+
|
|
22
|
+
- ignore vacation tag [\#3](https://github.com/limitusus/toggl-worktime/issues/3)
|
|
23
|
+
|
|
24
|
+
**Merged pull requests:**
|
|
25
|
+
|
|
26
|
+
- Config YAML [\#5](https://github.com/limitusus/toggl-worktime/pull/5) ([limitusus](https://github.com/limitusus))
|
|
27
|
+
- Specify year [\#4](https://github.com/limitusus/toggl-worktime/pull/4) ([limitusus](https://github.com/limitusus))
|
|
28
|
+
|
|
29
|
+
## [v0.2.0](https://github.com/limitusus/toggl-worktime/tree/v0.2.0) (2018-04-02)
|
|
30
|
+
[Full Changelog](https://github.com/limitusus/toggl-worktime/compare/v0.1.8...v0.2.0)
|
|
31
|
+
|
|
32
|
+
**Merged pull requests:**
|
|
33
|
+
|
|
34
|
+
- Remove const [\#2](https://github.com/limitusus/toggl-worktime/pull/2) ([limitusus](https://github.com/limitusus))
|
|
35
|
+
|
|
36
|
+
## [v0.1.8](https://github.com/limitusus/toggl-worktime/tree/v0.1.8) (2018-04-01)
|
|
37
|
+
[Full Changelog](https://github.com/limitusus/toggl-worktime/compare/v0.1.7...v0.1.8)
|
|
38
|
+
|
|
39
|
+
**Merged pull requests:**
|
|
40
|
+
|
|
41
|
+
- Export work\_time from driver [\#1](https://github.com/limitusus/toggl-worktime/pull/1) ([limitusus](https://github.com/limitusus))
|
|
42
|
+
|
|
43
|
+
## [v0.1.7](https://github.com/limitusus/toggl-worktime/tree/v0.1.7) (2017-09-19)
|
|
44
|
+
[Full Changelog](https://github.com/limitusus/toggl-worktime/compare/v0.1.6...v0.1.7)
|
|
45
|
+
|
|
46
|
+
## [v0.1.6](https://github.com/limitusus/toggl-worktime/tree/v0.1.6) (2017-09-19)
|
|
47
|
+
[Full Changelog](https://github.com/limitusus/toggl-worktime/compare/v0.1.5...v0.1.6)
|
|
48
|
+
|
|
49
|
+
## [v0.1.5](https://github.com/limitusus/toggl-worktime/tree/v0.1.5) (2017-08-15)
|
|
50
|
+
[Full Changelog](https://github.com/limitusus/toggl-worktime/compare/v0.1.4...v0.1.5)
|
|
51
|
+
|
|
52
|
+
## [v0.1.4](https://github.com/limitusus/toggl-worktime/tree/v0.1.4) (2017-07-07)
|
|
53
|
+
[Full Changelog](https://github.com/limitusus/toggl-worktime/compare/v0.1.3...v0.1.4)
|
|
54
|
+
|
|
55
|
+
## [v0.1.3](https://github.com/limitusus/toggl-worktime/tree/v0.1.3) (2017-07-07)
|
|
56
|
+
[Full Changelog](https://github.com/limitusus/toggl-worktime/compare/v0.1.2...v0.1.3)
|
|
57
|
+
|
|
58
|
+
## [v0.1.2](https://github.com/limitusus/toggl-worktime/tree/v0.1.2) (2017-07-05)
|
|
59
|
+
[Full Changelog](https://github.com/limitusus/toggl-worktime/compare/v0.1.1...v0.1.2)
|
|
60
|
+
|
|
61
|
+
## [v0.1.1](https://github.com/limitusus/toggl-worktime/tree/v0.1.1) (2017-07-05)
|
|
62
|
+
[Full Changelog](https://github.com/limitusus/toggl-worktime/compare/v0.1.0...v0.1.1)
|
|
63
|
+
|
|
64
|
+
## [v0.1.0](https://github.com/limitusus/toggl-worktime/tree/v0.1.0) (2017-07-05)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
data/README.md
CHANGED
|
@@ -13,6 +13,17 @@ worktime
|
|
|
13
13
|
2017-06-12 13:29:09 - 2017-06-12 19:23:23
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
or you can specify year (default is "this" year)
|
|
17
|
+
|
|
18
|
+
```console
|
|
19
|
+
$ toggl-worktime 2017 6 12
|
|
20
|
+
Tomoya Kabe
|
|
21
|
+
worktime
|
|
22
|
+
2017-06-12 09:54:34 - 2017-06-12 12:40:45
|
|
23
|
+
2017-06-12 13:29:09 - 2017-06-12 19:23:23
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
|
|
16
27
|
Weekend
|
|
17
28
|
|
|
18
29
|
```console
|
|
@@ -22,6 +33,47 @@ worktime
|
|
|
22
33
|
nil - nil
|
|
23
34
|
```
|
|
24
35
|
|
|
36
|
+
## Calendar mode
|
|
37
|
+
|
|
38
|
+
You can see your monthly worktime in calendar view
|
|
39
|
+
|
|
40
|
+
```console
|
|
41
|
+
$ toggl-worktime --calendar 2021 1
|
|
42
|
+
┌────────┬─────────────────┬─────────────────┬─────────────────┬─────────────────┬─────────────────┬────────┐
|
|
43
|
+
│Sun │Mon │Tue │Wed │Thu │Fri │Sat │
|
|
44
|
+
├────────┼─────────────────┼─────────────────┼─────────────────┼─────────────────┼─────────────────┼────────┤
|
|
45
|
+
│ │ │ │ │ │Day: 1 │Day: 2 │
|
|
46
|
+
│ │ │ │ │ │- │- │
|
|
47
|
+
│ │ │ │ │ │00:00:00 │00:00:00│
|
|
48
|
+
├────────┼─────────────────┼─────────────────┼─────────────────┼─────────────────┼─────────────────┼────────┤
|
|
49
|
+
│Day: 3 │Day: 4 │Day: 5 │Day: 6 │Day: 7 │Day: 8 │Day: 9 │
|
|
50
|
+
│- │- │10:00:00-18:00:00│10:00:00-18:00:00│10:00:00-18:00:00│10:00:00-18:00:00│- │
|
|
51
|
+
│00:00:00│00:00:00 │07:00:00 │07:00:00 │07:00:00 │07:00:00 │00:00:00│
|
|
52
|
+
├────────┼─────────────────┼─────────────────┼─────────────────┼─────────────────┼─────────────────┼────────┤
|
|
53
|
+
│Day: 10 │Day: 11 │Day: 12 │Day: 13 │Day: 14 │Day: 15 │Day: 16 │
|
|
54
|
+
│- │- │10:00:00-18:00:00│10:00:00-18:00:00│10:00:00-18:00:00│10:00:00-18:00:00│- │
|
|
55
|
+
│00:00:00│00:00:00 │07:00:00 │07:00:00 │07:00:00 │07:00:00 │00:00:00│
|
|
56
|
+
├────────┼─────────────────┼─────────────────┼─────────────────┼─────────────────┼─────────────────┼────────┤
|
|
57
|
+
│Day: 17 │Day: 18 │Day: 19 │Day: 20 │Day: 21 │Day: 22 │Day: 23 │
|
|
58
|
+
│- │10:00:00-18:00:00│10:00:00-18:00:00│10:00:00-18:00:00│10:00:00-18:00:00│10:00:00-18:00:00│- │
|
|
59
|
+
│00:00:00│07:00:00 │07:00:00 │07:00:00 │07:00:00 │07:00:00 │00:00:00│
|
|
60
|
+
├────────┼─────────────────┼─────────────────┼─────────────────┼─────────────────┼─────────────────┼────────┤
|
|
61
|
+
│Day: 24 │Day: 25 │Day: 26 │Day: 27 │Day: 28 │Day: 29 │Day: 30 │
|
|
62
|
+
│- │10:00:00-18:00:00│10:00:00-18:00:00│10:00:00-18:00:00│10:00:00-18:00:00│10:00:00-18:00:00│- │
|
|
63
|
+
│00:00:00│07:00:00 │07:00:00 │07:00:00 │07:00:00 │07:00:00 │00:00:00│
|
|
64
|
+
├────────┼─────────────────┼─────────────────┼─────────────────┼─────────────────┼─────────────────┼────────┤
|
|
65
|
+
│Day: 31 │ │ │ │ │ │ │
|
|
66
|
+
│- │ │ │ │ │ │ │
|
|
67
|
+
│00:00:00│ │ │ │ │ │ │
|
|
68
|
+
└────────┴─────────────────┴─────────────────┴─────────────────┴─────────────────┴─────────────────┴────────┘
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
You can change the beginning day of the week with `-b` option:
|
|
72
|
+
|
|
73
|
+
```console
|
|
74
|
+
$ toggl-worktime --calendar 2021 1 -b Mon
|
|
75
|
+
```
|
|
76
|
+
|
|
25
77
|
## Installation
|
|
26
78
|
|
|
27
79
|
Add this line to your application's Gemfile:
|
|
@@ -50,6 +102,36 @@ abcdef0123456789
|
|
|
50
102
|
|
|
51
103
|
You can get your API token from Toggl at your profile settings page.
|
|
52
104
|
|
|
105
|
+
NOTE: as of togglv8 v1.2.1, `.toggl` file **MUST NOT** end with a newline (`\010` or LF).
|
|
106
|
+
The recommended way to create the file is `echo -n 'YOUR_TOGGL_API_TOKEN' > ~/.toggl`.
|
|
107
|
+
This issue [will be fixed in the next togglv8 release](https://github.com/kanet77/togglv8/pull/21).
|
|
108
|
+
|
|
109
|
+
### Configuration
|
|
110
|
+
|
|
111
|
+
Place configuration file in `~/.toggl_worktime`.
|
|
112
|
+
Or you can specify your favorite path with `-c CONFIG` option.
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
# -*- yaml -*-
|
|
116
|
+
|
|
117
|
+
# working time interval within <working_interval_min> minutes is ignored
|
|
118
|
+
working_interval_min: 10
|
|
119
|
+
# Split the day at <day_begin_hour> o'clock
|
|
120
|
+
day_begin_hour: 6
|
|
121
|
+
# Timezone
|
|
122
|
+
timezone: Asia/Tokyo
|
|
123
|
+
|
|
124
|
+
# Time entries which match the condition below will not be counted as working time
|
|
125
|
+
# Multiple conditions can be specified as an array in top level,
|
|
126
|
+
# multiple keys (only "tags" for now) can be specified as hash keys in a condition,
|
|
127
|
+
# and multiple values can be specifeid as an array.
|
|
128
|
+
# Array conditions will be treated as "OR"
|
|
129
|
+
# Hash conditions will be treated as "AND"
|
|
130
|
+
ignore_conditions:
|
|
131
|
+
- tags:
|
|
132
|
+
- vacation
|
|
133
|
+
```
|
|
134
|
+
|
|
53
135
|
### Just run
|
|
54
136
|
|
|
55
137
|
```console
|
data/exe/toggl-worktime
CHANGED
|
@@ -3,28 +3,50 @@
|
|
|
3
3
|
|
|
4
4
|
$LOAD_PATH << File.expand_path("#{File.dirname __FILE__}/../lib")
|
|
5
5
|
|
|
6
|
+
require 'optparse'
|
|
6
7
|
require 'rubygems'
|
|
7
8
|
require 'toggl/worktime'
|
|
8
9
|
|
|
9
10
|
Version = Toggl::Worktime::VERSION
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
11
|
+
config_file = "#{ENV['HOME']}/.toggl_worktime"
|
|
12
|
+
mode = :default
|
|
13
|
+
week_begin = :Sun
|
|
14
|
+
debug = false
|
|
15
|
+
|
|
16
|
+
opt = OptionParser.new
|
|
17
|
+
opt.on('-c CONFIG', '--config CONFIG') { |v| config_file = v }
|
|
18
|
+
opt.on('-l', '--calendar', 'Calendar view mode') { mode = :calendar }
|
|
19
|
+
opt.on('-b', '--week-begin=VAL', 'Beginning of the week: Sun, Mon, etc.') { |v| week_begin = v }
|
|
20
|
+
opt.on('--debug') { |v| debug = v }
|
|
21
|
+
opt.parse!(ARGV)
|
|
22
|
+
|
|
23
|
+
config = Toggl::Worktime::Config.new(path: config_file)
|
|
24
|
+
driver = Toggl::Worktime::Driver.new(config: config)
|
|
25
|
+
p config if debug
|
|
26
|
+
|
|
27
|
+
case mode
|
|
28
|
+
when :calendar
|
|
29
|
+
raise ArgumentError, 'Usage: toggl-worktime --cal YEAR MONTH' if ARGV.size != 2
|
|
30
|
+
|
|
31
|
+
driver.calendar(week_begin, *ARGV.map(&:to_i)).write
|
|
32
|
+
else
|
|
33
|
+
case ARGV.size
|
|
34
|
+
when 3
|
|
35
|
+
year, month, day = *ARGV.map(&:to_i)
|
|
36
|
+
when 2
|
|
37
|
+
year = Time.now.year
|
|
38
|
+
month, day = *ARGV.map(&:to_i)
|
|
39
|
+
else
|
|
40
|
+
raise ArgumentError, 'Usage: toggl-worktime [YEAR] MONTH DAY'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
driver.merge!(year, month, day)
|
|
44
|
+
user = driver.me
|
|
45
|
+
|
|
46
|
+
puts user['fullname']
|
|
47
|
+
puts 'worktime'
|
|
48
|
+
|
|
49
|
+
driver.write
|
|
50
|
+
|
|
51
|
+
puts "Total worktime: #{driver.total_time}"
|
|
52
|
+
end
|
data/lib/toggl/worktime.rb
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'togglv8'
|
|
4
|
+
require 'date'
|
|
4
5
|
require 'json'
|
|
5
6
|
require 'toggl/worktime/version'
|
|
7
|
+
require 'toggl/worktime/config'
|
|
6
8
|
require 'toggl/worktime/merger'
|
|
7
9
|
require 'toggl/worktime/time'
|
|
8
10
|
require 'toggl/worktime/driver'
|
|
11
|
+
require 'toggl/worktime/calendar'
|
|
12
|
+
require 'tty-table'
|
|
9
13
|
|
|
10
14
|
module Toggl
|
|
11
15
|
# Main module
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Toggl
|
|
4
|
+
module Worktime
|
|
5
|
+
# Worktime Calendar
|
|
6
|
+
class Calendar
|
|
7
|
+
WEEK = %i[Sun Mon Tue Wed Thu Fri Sat].freeze
|
|
8
|
+
|
|
9
|
+
class UnknownWeekdayError < StandardError; end
|
|
10
|
+
|
|
11
|
+
def initialize(driver, zone_offset, week_begin, year, month)
|
|
12
|
+
@driver = driver
|
|
13
|
+
@zone_offset = zone_offset
|
|
14
|
+
@year = year
|
|
15
|
+
@month = month
|
|
16
|
+
today = ::Time.new
|
|
17
|
+
@days_in_month = Date.new(year, month, -1).day
|
|
18
|
+
@last_fetch_day = @days_in_month
|
|
19
|
+
@last_fetch_day = today.day if today.year == year && today.month == month && today.day < @days_in_month
|
|
20
|
+
@data = nil
|
|
21
|
+
@week_begin_day = week_begin.to_sym
|
|
22
|
+
raise UnknownWeekdayError if WEEK.index(@week_begin_day).nil?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def week
|
|
26
|
+
begin_index = WEEK.index(@week_begin_day)
|
|
27
|
+
WEEK.rotate(begin_index)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def write
|
|
31
|
+
fetch if @data.nil?
|
|
32
|
+
rotation = week.index(:Sun)
|
|
33
|
+
table = TTY::Table.new header: week
|
|
34
|
+
week_data = []
|
|
35
|
+
@day_data.each do |datum|
|
|
36
|
+
wday = datum.day.wday
|
|
37
|
+
# wday may be rotated
|
|
38
|
+
wday_index = (wday + rotation) % 7
|
|
39
|
+
week_data[wday_index] = datum.format
|
|
40
|
+
if wday_index == 6
|
|
41
|
+
table << week_data
|
|
42
|
+
week_data = []
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
# last week data may exist
|
|
46
|
+
unless week_data.length.zero?
|
|
47
|
+
# Padding
|
|
48
|
+
(7 - week_data.length).times do
|
|
49
|
+
week_data << nil
|
|
50
|
+
end
|
|
51
|
+
table << week_data
|
|
52
|
+
end
|
|
53
|
+
multi_renderer = TTY::Table::Renderer::Unicode.new(table, multiline: true)
|
|
54
|
+
multi_renderer.border.separator = :each_row
|
|
55
|
+
puts multi_renderer.render
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def fetch
|
|
59
|
+
@day_data = []
|
|
60
|
+
(1..@days_in_month).each do |day|
|
|
61
|
+
dateobj = Date.new(@year, @month, day)
|
|
62
|
+
day_datum = nil
|
|
63
|
+
if day <= @last_fetch_day
|
|
64
|
+
@driver.merge!(@year, @month, day)
|
|
65
|
+
time = @driver.total_time
|
|
66
|
+
begin_at = @driver.work_time.first[0]&.getlocal(@zone_offset)&.strftime('%T')
|
|
67
|
+
end_at = @driver.work_time.last[1]&.getlocal(@zone_offset)&.strftime('%T')
|
|
68
|
+
day_datum = Toggl::Worktime::Day.new(dateobj, time, begin_at, end_at)
|
|
69
|
+
else
|
|
70
|
+
day_datum = Toggl::Worktime::Day.new(dateobj, 0, '', '')
|
|
71
|
+
end
|
|
72
|
+
@day_data << day_datum
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# One-day datum
|
|
78
|
+
class Day
|
|
79
|
+
attr_reader :day
|
|
80
|
+
|
|
81
|
+
def initialize(day, time, begin_at, end_at)
|
|
82
|
+
@day = day
|
|
83
|
+
@time = time
|
|
84
|
+
@begin = begin_at
|
|
85
|
+
@end = end_at
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def format
|
|
89
|
+
"Day: #{day.day}\n#{@begin}-#{@end}\n#{@time}"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
|
|
5
|
+
module Toggl
|
|
6
|
+
module Worktime
|
|
7
|
+
# Config for Toggl::Worktime
|
|
8
|
+
class Config
|
|
9
|
+
attr_accessor :foo
|
|
10
|
+
|
|
11
|
+
ATTRS = %i[
|
|
12
|
+
working_interval_min
|
|
13
|
+
day_begin_hour
|
|
14
|
+
timezone
|
|
15
|
+
ignore_conditions
|
|
16
|
+
].freeze
|
|
17
|
+
|
|
18
|
+
ATTR_DEFAULTS = {
|
|
19
|
+
working_interval_min: 10,
|
|
20
|
+
day_begin_hour: 6,
|
|
21
|
+
timezone: 'Asia/Tokyo',
|
|
22
|
+
ignore_conditions: []
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
ATTRS.each do |attr|
|
|
26
|
+
attr_accessor attr
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def initialize(args)
|
|
30
|
+
c = self.class.load_config(args[:path])
|
|
31
|
+
attr_set(c)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class << self
|
|
35
|
+
def load_config(path)
|
|
36
|
+
YAML.safe_load(File.open(path).read).transform_keys(&:to_sym)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def attr_set(hash)
|
|
43
|
+
ATTRS.each do |k|
|
|
44
|
+
send((k.to_s + '=').to_sym, hash.key?(k) ? hash[k] : ATTR_DEFAULTS[k])
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -4,30 +4,57 @@ module Toggl
|
|
|
4
4
|
module Worktime
|
|
5
5
|
# Toggle API driver
|
|
6
6
|
class Driver
|
|
7
|
+
ONE_DAY_SECONDS = 86_400
|
|
8
|
+
|
|
7
9
|
attr_reader :toggl
|
|
8
10
|
attr_reader :work_time
|
|
9
11
|
|
|
10
|
-
def initialize
|
|
12
|
+
def initialize(config:)
|
|
11
13
|
@toggl = TogglV8::API.new
|
|
14
|
+
@config = config
|
|
12
15
|
@merger = nil
|
|
13
16
|
@work_time = nil
|
|
17
|
+
@zone_offset = Toggl::Worktime::Time.zone_offset(@config.timezone)
|
|
18
|
+
@calendar = nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def calendar(week_begin, year, month)
|
|
22
|
+
@calendar = Toggl::Worktime::Calendar.new(self, @zone_offset, week_begin, year, month)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def time_entries(year, month, day)
|
|
26
|
+
beginning_day = ::Time.new(
|
|
27
|
+
year, month, day, @config.day_begin_hour, 0, 0, @zone_offset
|
|
28
|
+
)
|
|
29
|
+
ending_day = beginning_day + ONE_DAY_SECONDS
|
|
30
|
+
start_iso = beginning_day.strftime('%FT%T%:z')
|
|
31
|
+
end_iso = ending_day.strftime('%FT%T%:z')
|
|
32
|
+
toggl.get_time_entries(start_date: start_iso, end_date: end_iso)
|
|
14
33
|
end
|
|
15
34
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
35
|
+
# time_entries filter with @config.ignore_conditions
|
|
36
|
+
def filter_entries(entries)
|
|
37
|
+
pass_l = lambda { |entry|
|
|
38
|
+
@config.ignore_conditions.none? do |cond|
|
|
39
|
+
cond.keys.all? do |key|
|
|
40
|
+
case key
|
|
41
|
+
when 'tags'
|
|
42
|
+
entry['tags']&.any? { |t| cond[key].include?(t) }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
}
|
|
47
|
+
entries.select { |e| pass_l.call(e) }
|
|
22
48
|
end
|
|
23
49
|
|
|
24
50
|
def me
|
|
25
51
|
@toggl.me(true)
|
|
26
52
|
end
|
|
27
53
|
|
|
28
|
-
def merge!(month, day
|
|
29
|
-
time_entries = time_entries(month, day
|
|
30
|
-
|
|
54
|
+
def merge!(year, month, day)
|
|
55
|
+
time_entries = time_entries(year, month, day)
|
|
56
|
+
time_entries = filter_entries(time_entries)
|
|
57
|
+
@merger = Toggl::Worktime::Merger.new(time_entries, @config)
|
|
31
58
|
@work_time = @merger.merge
|
|
32
59
|
end
|
|
33
60
|
|
|
@@ -39,17 +66,16 @@ module Toggl
|
|
|
39
66
|
end
|
|
40
67
|
end
|
|
41
68
|
|
|
42
|
-
def time_expr(
|
|
43
|
-
|
|
69
|
+
def time_expr(time)
|
|
70
|
+
time ? time.getlocal(@zone_offset).strftime('%F %T') : 'nil'
|
|
44
71
|
end
|
|
45
72
|
|
|
46
73
|
def total_time
|
|
47
|
-
|
|
48
|
-
total_seconds = (time * 86400).to_i
|
|
74
|
+
total_seconds = @merger.total_time.to_i
|
|
49
75
|
hours = total_seconds / (60 * 60)
|
|
50
76
|
minutes = (total_seconds - (hours * 60 * 60)) / 60
|
|
51
77
|
seconds = total_seconds % 60
|
|
52
|
-
format(
|
|
78
|
+
format('%02d:%02d:%02d', hours, minutes, seconds)
|
|
53
79
|
end
|
|
54
80
|
end
|
|
55
81
|
end
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'time'
|
|
4
|
+
|
|
3
5
|
module Toggl
|
|
4
6
|
module Worktime
|
|
5
7
|
# Time-entries merger
|
|
6
8
|
class Merger
|
|
7
9
|
attr_reader :total_time
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
ONE_MINUTE_SECONDS = 60
|
|
12
|
+
|
|
13
|
+
def initialize(time_entries, config)
|
|
10
14
|
@time_entries = time_entries
|
|
15
|
+
@config = config
|
|
11
16
|
@current_start = nil
|
|
12
17
|
@current_stop = nil
|
|
13
18
|
@continuing = true
|
|
@@ -23,34 +28,47 @@ module Toggl
|
|
|
23
28
|
next
|
|
24
29
|
end
|
|
25
30
|
work_time << [@current_start, @current_stop]
|
|
31
|
+
count_total_time
|
|
26
32
|
@current_start = start
|
|
27
33
|
@current_stop = stop
|
|
28
34
|
end
|
|
29
35
|
work_time << [@current_start, @last_stop]
|
|
36
|
+
count_total_time
|
|
30
37
|
work_time
|
|
31
38
|
end
|
|
32
39
|
|
|
40
|
+
def count_total_time
|
|
41
|
+
return if @current_start.nil? || @current_stop.nil?
|
|
42
|
+
|
|
43
|
+
@total_time += @current_stop - @current_start
|
|
44
|
+
end
|
|
45
|
+
|
|
33
46
|
def time_entries_each
|
|
34
|
-
zone_offset = Toggl::Worktime::Time.zone_offset(
|
|
47
|
+
zone_offset = Toggl::Worktime::Time.zone_offset(@config.timezone)
|
|
35
48
|
@time_entries.each do |te|
|
|
36
49
|
start = parse_date(te['start'], zone_offset)
|
|
37
50
|
stop = parse_date(te['stop'], zone_offset)
|
|
38
51
|
@last_stop = stop
|
|
39
52
|
@current_start = start if @current_start.nil?
|
|
40
53
|
@current_stop = stop if @current_stop.nil?
|
|
41
|
-
|
|
54
|
+
if start.nil? || stop.nil?
|
|
55
|
+
warn 'start or stop time is nil: total time may be incomplete'
|
|
56
|
+
end
|
|
42
57
|
yield [start, stop]
|
|
43
58
|
end
|
|
44
59
|
end
|
|
45
60
|
|
|
46
61
|
def parse_date(date, zone_offset)
|
|
47
62
|
return nil if date.nil?
|
|
48
|
-
|
|
63
|
+
|
|
64
|
+
::Time.parse(date).getlocal(zone_offset)
|
|
49
65
|
end
|
|
50
66
|
|
|
51
67
|
def continuing(start)
|
|
52
|
-
|
|
53
|
-
|
|
68
|
+
return true if @current_stop.nil?
|
|
69
|
+
|
|
70
|
+
interval = (start - @current_stop) / ONE_MINUTE_SECONDS
|
|
71
|
+
@continuing = interval < @config.working_interval_min
|
|
54
72
|
end
|
|
55
73
|
end
|
|
56
74
|
end
|
data/lib/toggl/worktime/time.rb
CHANGED
|
@@ -4,11 +4,11 @@ module Toggl
|
|
|
4
4
|
module Worktime
|
|
5
5
|
# Timezone
|
|
6
6
|
module Time
|
|
7
|
-
#
|
|
7
|
+
# Seconds
|
|
8
8
|
def self.zone_offset(timezone)
|
|
9
9
|
tz = ENV['TZ']
|
|
10
10
|
ENV['TZ'] = timezone
|
|
11
|
-
offset =
|
|
11
|
+
offset = ::Time.now.utc_offset
|
|
12
12
|
ENV['TZ'] = tz
|
|
13
13
|
offset
|
|
14
14
|
end
|
data/toggl-worktime.gemspec
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
# coding: utf-8
|
|
2
1
|
# frozen_string_literal: true
|
|
3
2
|
|
|
4
|
-
lib = File.expand_path('
|
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
|
5
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
6
5
|
require 'toggl/worktime/version'
|
|
7
6
|
|
|
@@ -23,12 +22,13 @@ Gem::Specification.new do |spec|
|
|
|
23
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
24
23
|
spec.require_paths = ['lib']
|
|
25
24
|
|
|
26
|
-
spec.add_dependency 'togglv8'
|
|
27
25
|
spec.add_dependency 'awesome_print'
|
|
26
|
+
spec.add_dependency 'togglv8'
|
|
27
|
+
spec.add_dependency 'tty-table'
|
|
28
|
+
spec.add_development_dependency 'bundler', '~> 1.15'
|
|
28
29
|
spec.add_development_dependency 'pry'
|
|
30
|
+
spec.add_development_dependency 'rake', '>= 12.3.3'
|
|
29
31
|
spec.add_development_dependency 'rb-readline'
|
|
30
|
-
spec.add_development_dependency 'rubocop'
|
|
31
|
-
spec.add_development_dependency 'bundler', '~> 1.15'
|
|
32
|
-
spec.add_development_dependency 'rake', '~> 10.0'
|
|
33
32
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
|
33
|
+
spec.add_development_dependency 'rubocop'
|
|
34
34
|
end
|
metadata
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: toggl-worktime
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tomoya KABE
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-02-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
14
|
+
name: awesome_print
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
@@ -25,7 +25,7 @@ dependencies:
|
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '0'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
28
|
+
name: togglv8
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - ">="
|
|
@@ -39,13 +39,13 @@ dependencies:
|
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: '0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
42
|
+
name: tty-table
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
45
|
- - ">="
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
47
|
version: '0'
|
|
48
|
-
type: :
|
|
48
|
+
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
@@ -53,21 +53,21 @@ dependencies:
|
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '0'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
56
|
+
name: bundler
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
|
-
- - "
|
|
59
|
+
- - "~>"
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '
|
|
61
|
+
version: '1.15'
|
|
62
62
|
type: :development
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
|
-
- - "
|
|
66
|
+
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
68
|
+
version: '1.15'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
|
-
name:
|
|
70
|
+
name: pry
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
73
|
- - ">="
|
|
@@ -81,33 +81,33 @@ dependencies:
|
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: '0'
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name:
|
|
84
|
+
name: rake
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
|
-
- - "
|
|
87
|
+
- - ">="
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
|
-
version:
|
|
89
|
+
version: 12.3.3
|
|
90
90
|
type: :development
|
|
91
91
|
prerelease: false
|
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
93
|
requirements:
|
|
94
|
-
- - "
|
|
94
|
+
- - ">="
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
|
-
version:
|
|
96
|
+
version: 12.3.3
|
|
97
97
|
- !ruby/object:Gem::Dependency
|
|
98
|
-
name:
|
|
98
|
+
name: rb-readline
|
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
|
100
100
|
requirements:
|
|
101
|
-
- - "
|
|
101
|
+
- - ">="
|
|
102
102
|
- !ruby/object:Gem::Version
|
|
103
|
-
version: '
|
|
103
|
+
version: '0'
|
|
104
104
|
type: :development
|
|
105
105
|
prerelease: false
|
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
107
|
requirements:
|
|
108
|
-
- - "
|
|
108
|
+
- - ">="
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
|
-
version: '
|
|
110
|
+
version: '0'
|
|
111
111
|
- !ruby/object:Gem::Dependency
|
|
112
112
|
name: rspec
|
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -122,6 +122,20 @@ dependencies:
|
|
|
122
122
|
- - "~>"
|
|
123
123
|
- !ruby/object:Gem::Version
|
|
124
124
|
version: '3.0'
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: rubocop
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - ">="
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '0'
|
|
132
|
+
type: :development
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - ">="
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '0'
|
|
125
139
|
description: Summarise Toggl Time Entries
|
|
126
140
|
email:
|
|
127
141
|
- limit.usus@gmail.com
|
|
@@ -134,6 +148,7 @@ files:
|
|
|
134
148
|
- ".rspec"
|
|
135
149
|
- ".rubocop.yml"
|
|
136
150
|
- ".travis.yml"
|
|
151
|
+
- CHANGELOG.md
|
|
137
152
|
- CODE_OF_CONDUCT.md
|
|
138
153
|
- Gemfile
|
|
139
154
|
- LICENSE.txt
|
|
@@ -143,6 +158,8 @@ files:
|
|
|
143
158
|
- bin/setup
|
|
144
159
|
- exe/toggl-worktime
|
|
145
160
|
- lib/toggl/worktime.rb
|
|
161
|
+
- lib/toggl/worktime/calendar.rb
|
|
162
|
+
- lib/toggl/worktime/config.rb
|
|
146
163
|
- lib/toggl/worktime/driver.rb
|
|
147
164
|
- lib/toggl/worktime/merger.rb
|
|
148
165
|
- lib/toggl/worktime/time.rb
|
|
@@ -167,8 +184,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
167
184
|
- !ruby/object:Gem::Version
|
|
168
185
|
version: '0'
|
|
169
186
|
requirements: []
|
|
170
|
-
|
|
171
|
-
rubygems_version: 2.7.3
|
|
187
|
+
rubygems_version: 3.1.4
|
|
172
188
|
signing_key:
|
|
173
189
|
specification_version: 4
|
|
174
190
|
summary: '["Summarise Toggl Time Entries", "Summarise Toggl Time Entries", "https://github.com/limitusus/toggl-worktime"]'
|