togman 0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+