gpuzzletime 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c3f853932bdf602db7566b6e122e7b130f09b55f8520da2922c178a621bad930
4
+ data.tar.gz: 2be9f507dc5f3501a3f204505a255c86f2db62e7262f9339a0ba90ca457f191c
5
+ SHA512:
6
+ metadata.gz: a2ba71e0e22135f99f34e38ed95cf37342d20f79f92f8f78b19a53ca5a8df0469c07562a4a508fc006797899e5a99284f4a65398b6c1f5b93ab359532460ab9b
7
+ data.tar.gz: 55b6f2fa52083b8708d59cc5c9bb2b430945151ff013fad5b0993f8eae495da12782082ce6d8d15d3e8d82bce4296e418c225fc9906d8f7c50c87406b621ad0f
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ gpuzzletime
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.5.1
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.1
4
+ - 2.4.2
5
+ before_install: gem install bundler -v 1.11.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gpuzzletime.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017-2018 Matthias Viehweger
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # gPuzzleTime
2
+
3
+ small tooling to transfer timelog-entries from gtimelog's timelog.txt to the PuzzleTime TimeTracking Website.
4
+
5
+ ## Approach
6
+
7
+ - [x] read timelog.txt
8
+ - [x] from known location
9
+ - [ ] later: configure location?
10
+ - [ ] later: auto-detect location?
11
+ - [x] parse out last day
12
+ - [x] especially start/end-times for each entry
13
+ - [x] date - ticket - description
14
+ - [x] later: parse out specific day
15
+ - [x] open N browser instances with the time entry data
16
+ - [x] without selected account
17
+ - [x] infer time-account from ticket-format
18
+ - [x] support user-supplied ticket-parsers
19
+ - [x] get ticket-parser from tags
20
+ - [ ] merge equal adjacent entries into one
21
+ - [ ] complete login/entry automation
22
+ - [ ] login
23
+ - [ ] store cookie
24
+ - [ ] make entries
25
+ - [ ] open day in browser for review
26
+ - [ ] avoid duplicate entries
27
+ - [ ] start/end time as indicator?
28
+ - [ ] offer rounding times to the next 5, 10 or 15 minutes
29
+ - [ ] allow to add entries from the command-line
30
+
31
+
32
+ ## Installation
33
+
34
+ Install it with:
35
+
36
+ $ gem install gpuzzletime
37
+
38
+ ## Usage
39
+
40
+ $ gpuzzletime ACTION DATE
41
+
42
+ ### Actions
43
+
44
+ Currently supported actions are
45
+
46
+ - show
47
+ - upload
48
+
49
+ ### Date-Identifier
50
+
51
+ To handle a specific date, the format YYYY-MM-DD is expected, e.g. 2017-12-25. Please note that you should not work on that day, unless you bring presents.
52
+
53
+ For reusability in a shell-history the following keywords are supported:
54
+
55
+ - today
56
+ - yesterday
57
+
58
+ If nothing is specified, the action is applied to all entries.
59
+
60
+ ## Development
61
+
62
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. Run `bundle exec gpuzzletime` to use the gem in this directory, ignoring other installed copies of this gem.
63
+
64
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
65
+
66
+ ## Contributing
67
+
68
+ Bug reports and pull requests are welcome on GitHub at https://github.com/kronn/gpuzzletime.
69
+
70
+
71
+ ## License
72
+
73
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "gpuzzletime"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/exe/gpuzzletime ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/gpuzzletime'
5
+
6
+ Gpuzzletime::App.new(ARGV).run
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'gpuzzletime/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "gpuzzletime"
8
+ spec.version = Gpuzzletime::VERSION
9
+ spec.authors = ["Matthias Viehweger"]
10
+ spec.email = ["kronn@kronn.de"]
11
+
12
+ spec.summary = %q{Move time-entries from gTimelog to PuzzleTime}
13
+ # spec.description = %q{}
14
+ spec.homepage = "https://github.com/kronn/gpuzzletime"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.11"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "rspec", "~> 3.0"
25
+ spec.add_development_dependency "rubocop", "~> 0.50"
26
+ end
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+ require 'erb'
5
+ require 'pathname'
6
+
7
+ # Wrapper for everything
8
+ module Gpuzzletime
9
+ class App
10
+ def initialize(args)
11
+ @base_url = 'https://time.puzzle.ch'
12
+
13
+ @command = (args[0] || :show).to_sym
14
+
15
+ case @command
16
+ when :show, :upload
17
+ @date = named_dates(args[1]) || :all
18
+ when :edit
19
+ @file = args[1]
20
+ else
21
+ raise ArgumentError, "Unsupported Command #{@command}"
22
+ end
23
+ end
24
+
25
+ def run
26
+ launch_editor if @command == :edit
27
+
28
+ @entries = {}
29
+
30
+ parse(read).each do |date, entries|
31
+ # this is mixing preparation, assembly and output, but gets the job done
32
+ next unless date # guard against the machine
33
+ next unless @date == :all || @date == date # limit to one day if passed
34
+ @entries[date] = []
35
+
36
+ start = nil # at the start of the day, we have no previous end
37
+
38
+ entries.each do |entry|
39
+ finish = entry[:time] # we use that twice
40
+ hidden = entry[:description].match(/\*\*$/) # hide lunch and breaks
41
+
42
+ if start && !hidden
43
+ case @command # assemble data according to command
44
+ when :show
45
+ @entries[date] << [
46
+ start, '-', finish,
47
+ [
48
+ entry[:ticket],
49
+ entry[:description],
50
+ entry[:tags],
51
+ infer_account(entry),
52
+ ].compact.join(' ∴ '),
53
+ ].compact.join(' ')
54
+ when :upload
55
+ @entries[date] << [start, entry]
56
+ end
57
+ end
58
+
59
+ start = finish # store previous ending for nice display of next entry
60
+ end
61
+ end
62
+
63
+ case @command
64
+ when :show
65
+ @entries.each do |date, entries|
66
+ puts date, '----------'
67
+ entries.each do |entry|
68
+ puts entry
69
+ end
70
+ puts nil
71
+ end
72
+ when :upload
73
+ @entries.each do |date, entries|
74
+ puts "Uploading #{date}"
75
+ entries.each do |start, entry|
76
+ open_browser(start, entry)
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ def open_browser(start, entry)
85
+ url = "#{@base_url}/ordertimes/new?#{url_options(start, entry)}"
86
+ system "gnome-open '#{url}' > /dev/null 2> /dev/null"
87
+ end
88
+
89
+ def launch_editor
90
+ editor = `which $EDITOR`.chomp
91
+
92
+ file = @file.nil? ? timelog_txt : parser_file(@file)
93
+
94
+ exec "#{editor} #{file}"
95
+ end
96
+
97
+ def url_options(start, entry)
98
+ {
99
+ work_date: entry[:date],
100
+ 'ordertime[ticket]': entry[:ticket],
101
+ 'ordertime[description]': entry[:description],
102
+ 'ordertime[from_start_time]': start,
103
+ 'ordertime[to_end_time]': entry[:time],
104
+ 'ordertime[account_id]': infer_account(entry),
105
+ }
106
+ .map { |key, value| [key, ERB::Util.url_encode(value)].join('=') }
107
+ .join('&')
108
+ end
109
+
110
+ def named_dates(date)
111
+ case date
112
+ when 'yesterday' then Date.today.prev_day.to_s
113
+ when 'today' then Date.today.to_s
114
+ else date
115
+ end
116
+ end
117
+
118
+ def timelog_txt
119
+ Pathname.new('~/.local/share/gtimelog/timelog.txt').expand_path
120
+ end
121
+
122
+ def read
123
+ timelog_txt.read
124
+ end
125
+
126
+ def parse(data)
127
+ data.split("\n")
128
+ .map { |line| tokenize(line) }
129
+ .group_by { |match| match && match[:date] }
130
+ .to_a
131
+ end
132
+
133
+ def tokenize(line)
134
+ re_date = /(?<date>\d{4}-\d{2}-\d{2})/
135
+ re_time = /(?<time>\d{2}:\d{2})/
136
+ re_tick = /(?:(?<ticket>.*?): )/
137
+ re_desc = /(?<description>.*?)/
138
+ re_tags = /(?: -- (?<tags>.*)?)/
139
+
140
+ regexp = /^#{re_date} #{re_time}: #{re_tick}?#{re_desc}#{re_tags}?$/
141
+ line.match(regexp)
142
+ end
143
+
144
+ def parser_file(parser_name)
145
+ Pathname.new("~/.config/gpuzzletime/parsers/#{parser_name}") # security-hole, prevent relative paths!
146
+ .expand_path
147
+ end
148
+
149
+ def infer_account(entry)
150
+ return unless entry[:tags]
151
+
152
+ tags = entry[:tags].split
153
+ parser_name = tags.shift
154
+
155
+ parser = parser_file(parser_name)
156
+
157
+ return unless parser.exist?
158
+
159
+ `#{parser} "#{entry[:ticket]}" "#{entry[:description]}" #{tags}`.chomp # maybe only execute if parser is in correct dir?
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Version
4
+ module Gpuzzletime
5
+ VERSION = '0.1.0'
6
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift File.dirname(__FILE__)
4
+
5
+ # Autoloading and such
6
+ module Gpuzzletime
7
+ autoload :App, 'gpuzzletime/app'
8
+ autoload :VERSION, 'gpuzzletime/version'
9
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gpuzzletime
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Matthias Viehweger
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-06-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.50'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.50'
69
+ description:
70
+ email:
71
+ - kronn@kronn.de
72
+ executables:
73
+ - gpuzzletime
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - ".rspec"
79
+ - ".ruby-gemset"
80
+ - ".ruby-version"
81
+ - ".travis.yml"
82
+ - Gemfile
83
+ - LICENSE.txt
84
+ - README.md
85
+ - Rakefile
86
+ - bin/console
87
+ - bin/setup
88
+ - exe/gpuzzletime
89
+ - gpuzzletime.gemspec
90
+ - lib/gpuzzletime.rb
91
+ - lib/gpuzzletime/app.rb
92
+ - lib/gpuzzletime/version.rb
93
+ homepage: https://github.com/kronn/gpuzzletime
94
+ licenses:
95
+ - MIT
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.7.6
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: Move time-entries from gTimelog to PuzzleTime
117
+ test_files: []