togman 0.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.
Files changed (4) hide show
  1. data/bin/togman +58 -0
  2. data/lib/mantis.rb +44 -0
  3. data/lib/toggl.rb +63 -0
  4. metadata +135 -0
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+ require "rubygems"
3
+ require "patron"
4
+ require "pp"
5
+ require "json"
6
+ require 'savon'
7
+ require 'highline/import'
8
+ require 'trollop'
9
+ require 'yaml'
10
+
11
+ require 'toggl.rb'
12
+ require 'mantis.rb'
13
+
14
+ configfile = ENV['HOME'] + '/.togmanrc'
15
+ if !File.file? configfile
16
+ puts 'Cannot open ' + configfile
17
+ exit
18
+ end
19
+
20
+ config = YAML::load_file configfile
21
+ pp config
22
+
23
+ Savon.configure do |setting|
24
+ setting.log = false # disable logging
25
+ # config.log_level = :info # changing the log level
26
+ end
27
+
28
+ opts = Trollop::options do
29
+ opt :dryrun, "Preview time to be logged without saving to Mantis", :short => 'd'
30
+ end
31
+
32
+ if !opts.dryrun
33
+ pass = ask('Password:') {|q| q.echo = '*'}
34
+ end
35
+
36
+ t = Toggl.new config['toggl_api_key'], config['nonbill']
37
+ m = Mantis.new config['user'], pass, config['mantis_url']
38
+
39
+ if !opts.dryrun
40
+ t.today.each do |ims, data|
41
+ if !m.issue_exists ims
42
+ raise "Issue not found #{ims}"
43
+ end
44
+ end
45
+ end
46
+
47
+ total = 0
48
+ free = []
49
+ t.today.each do |ims, data|
50
+ data.each do |item|
51
+ if !opts.dryrun
52
+ m.add_note ims, item[:desc], item[:duration]
53
+ end
54
+ p ims.to_s + " " + item[:desc] + " " + item[:duration].to_s + " " + item[:orig].to_s
55
+ total += item[:duration]
56
+ end
57
+ end
58
+ p "TOTAL: " + total.to_s
@@ -0,0 +1,44 @@
1
+ class Mantis
2
+ def initialize (user, password, url)
3
+ @client = Savon::Client.new do |wdsl|
4
+ wdsl.document = url
5
+ end
6
+ @client.wsdl.endpoint = url
7
+ @user = user
8
+ @password = password
9
+ end
10
+
11
+ def issue_exists (issue_id)
12
+ user = @user
13
+ password = @password
14
+ issue = @client.request "mc_issue_exists" do
15
+ soap.body = <<XML
16
+ <username>#{user}</username>
17
+ <password>#{password}</password>
18
+ <issue_id>#{issue_id}</issue_id>
19
+ XML
20
+ end
21
+
22
+ issue.to_hash[:mc_issue_exists_response][:return]
23
+ end
24
+
25
+ def add_note (issue_id, text, time_tracking)
26
+ user = @user
27
+ password = @password
28
+ res = @client.request "mc_issue_note_add" do
29
+ soap.body = <<XML
30
+ <username>#{user}</username>
31
+ <password>#{password}</password>
32
+ <issue_id>#{issue_id}</issue_id>
33
+ <note>
34
+ <text>#{text}</text>
35
+ <view_state>
36
+ <name>private</name>
37
+ <id>50</id>
38
+ </view_state>
39
+ <time_tracking>#{time_tracking}</time_tracking>
40
+ </note>
41
+ XML
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,63 @@
1
+ class Toggl
2
+ def initialize (api_key, nonbill)
3
+ @api_key = api_key
4
+ @nonbill = nonbill
5
+
6
+ @sess = Patron::Session.new
7
+ @sess.base_url = "https://www.toggl.com"
8
+ @sess.username = api_key
9
+ @sess.password = "api_token"
10
+ end
11
+
12
+ def today
13
+ from = Time.utc(Time.now.year, Time.now.month, Time.now.day).iso8601
14
+ to = Time.utc(Time.now.year, Time.now.month, Time.now.day, 23, 59, 59).iso8601
15
+ return self.entries(from, to)
16
+ end
17
+
18
+ def entries (from, to)
19
+ log = {}
20
+ res = @sess.get('/api/v5/time_entries.json?start_date=' + from + '&end_date=' + to).body
21
+ JSON.parse(res)["data"].each do |item|
22
+ raw = item["description"]
23
+
24
+ # Check all entries start with a issue number
25
+ if !res = raw.match(/^([0-9]+) (.+)$/)
26
+ raise 'Item does not have an issue number: ' + raw
27
+ end
28
+
29
+ ims = res[1]
30
+ desc = res[2]
31
+ duration = (item["duration"] / 60)
32
+
33
+ if log[ims] == nil
34
+ log[ims] = []
35
+ end
36
+
37
+ # Squash times with the same descriptions together
38
+ exists = false
39
+ log[ims].each do |exist|
40
+ if exist[:desc] == desc
41
+ exist[:duration] += duration
42
+ exists = true
43
+ end
44
+ end
45
+
46
+ # TOOD: Rounding should be on the total time for an issue.
47
+ # not per note... either need to bunch them together or
48
+ # round the final note???
49
+
50
+ free = false
51
+ if !@nonbill.member? ims.to_i
52
+ orig = duration
53
+ duration = ((duration.to_f/10).ceil*10).round
54
+ free = true
55
+ end
56
+
57
+ if !exists
58
+ log[ims].push({:desc => desc, :duration => duration, :orig => orig})
59
+ end
60
+ end
61
+ return log
62
+ end
63
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: togman
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ version: "0.1"
9
+ platform: ruby
10
+ authors:
11
+ - Benjamin Johnson
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+
16
+ date: 2011-10-03 00:00:00 +01:00
17
+ default_executable: bin/togman
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: patron
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ segments:
27
+ - 0
28
+ - 4
29
+ - 16
30
+ version: 0.4.16
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: json
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ segments:
41
+ - 1
42
+ - 6
43
+ - 1
44
+ version: 1.6.1
45
+ type: :runtime
46
+ version_requirements: *id002
47
+ - !ruby/object:Gem::Dependency
48
+ name: savon
49
+ prerelease: false
50
+ requirement: &id003 !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ segments:
55
+ - 0
56
+ - 9
57
+ - 7
58
+ version: 0.9.7
59
+ type: :runtime
60
+ version_requirements: *id003
61
+ - !ruby/object:Gem::Dependency
62
+ name: highline
63
+ prerelease: false
64
+ requirement: &id004 !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ segments:
69
+ - 1
70
+ - 6
71
+ - 2
72
+ version: 1.6.2
73
+ type: :runtime
74
+ version_requirements: *id004
75
+ - !ruby/object:Gem::Dependency
76
+ name: trollop
77
+ prerelease: false
78
+ requirement: &id005 !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ segments:
83
+ - 1
84
+ - 16
85
+ - 2
86
+ version: 1.16.2
87
+ type: :runtime
88
+ version_requirements: *id005
89
+ description: ""
90
+ email:
91
+ - ben@benpjohnson.com
92
+ executables:
93
+ - togman
94
+ extensions: []
95
+
96
+ extra_rdoc_files: []
97
+
98
+ files:
99
+ - bin/togman
100
+ - lib/mantis.rb
101
+ - lib/toggl.rb
102
+ has_rdoc: true
103
+ homepage: http://benpjohnson.com
104
+ licenses: []
105
+
106
+ post_install_message:
107
+ rdoc_options: []
108
+
109
+ require_paths:
110
+ - lib
111
+ required_ruby_version: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ segments:
116
+ - 0
117
+ version: "0"
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ segments:
123
+ - 1
124
+ - 3
125
+ - 6
126
+ version: 1.3.6
127
+ requirements: []
128
+
129
+ rubyforge_project:
130
+ rubygems_version: 1.3.6
131
+ signing_key:
132
+ specification_version: 3
133
+ summary: Transfer time from Toggl to Mantis
134
+ test_files: []
135
+