achoo 0.4.2 → 0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +13 -0
- data/README.rdoc +26 -22
- data/lib/achoo/achievo/hour_administration_form.rb +2 -3
- data/lib/achoo/achievo/hour_registration_form.rb +12 -15
- data/lib/achoo/achievo/hour_registration_form_ranged.rb +5 -2
- data/lib/achoo/achievo/lock_month_form.rb +1 -5
- data/lib/achoo/achievo/login_form.rb +3 -3
- data/lib/achoo/app.rb +27 -28
- data/lib/achoo/awake.rb +1 -1
- data/lib/achoo/extensions.rb +4 -0
- data/lib/achoo/ical.rb +6 -2
- data/lib/achoo/plugin/awake.rb +23 -0
- data/lib/achoo/plugin/ical.rb +47 -0
- data/lib/achoo/plugin/vcs.rb +26 -0
- data/lib/achoo/plugin_base.rb +6 -0
- data/lib/achoo/rc_loader.rb +9 -0
- data/lib/achoo/temporal/timespan.rb +3 -3
- data/lib/achoo/term.rb +7 -3
- data/lib/achoo/term/table.rb +5 -6
- data/lib/achoo/ui/commands.rb +12 -12
- data/lib/achoo/ui/date_chooser.rb +1 -1
- data/lib/achoo/ui/exception_handling.rb +1 -1
- data/lib/achoo/ui/register_hours.rb +50 -50
- data/lib/achoo/vcs/git.rb +5 -3
- data/test/acceptance/test_flexi_time.rb +41 -0
- data/test/acceptance/test_lock_month.rb +39 -0
- data/test/acceptance/test_register_hours.rb +161 -0
- data/test/lib/achievo_mock.rb +76 -0
- data/test/lib/achoo_runner.rb +54 -0
- data/test/lib/test_helpers.rb +43 -0
- data/test/unit/test_achievo_date_field.rb +34 -0
- data/test/unit/test_awake.rb +98 -0
- data/test/unit/test_extensions_array.rb +25 -0
- data/test/unit/test_system_cstruct.rb +28 -0
- data/test/unit/test_system_log_entry.rb +31 -0
- data/test/unit/test_term_menu.rb +71 -0
- data/test/unit/test_term_table.rb +52 -0
- data/test/unit/test_timespan.rb +48 -0
- data/test/unit/test_ui_date_chooser.rb +36 -0
- metadata +101 -74
data/CHANGES
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
2011-06-10: version 0.5
|
2
|
+
|
3
|
+
- Added support for plugins.
|
4
|
+
|
5
|
+
- Added tab completion for the hour registration all projects chooser.
|
6
|
+
|
7
|
+
- Added support for advanced line editing (readline).
|
8
|
+
|
9
|
+
- More user friendly configuration of ical. Merge :host, :port, and
|
10
|
+
:path into :url.
|
11
|
+
|
12
|
+
- Caching the list of all projects in hour registration.
|
13
|
+
|
1
14
|
2010-05-11: version 0.4.2
|
2
15
|
|
3
16
|
- Fixed problem with identifying the halt event in the awake log.
|
data/README.rdoc
CHANGED
@@ -5,26 +5,34 @@ works by scraping achievo web pages and sending HTTP requests.
|
|
5
5
|
|
6
6
|
== INSTALL
|
7
7
|
|
8
|
-
These instructions are for installing on Ubuntu
|
9
|
-
|
10
|
-
well.
|
8
|
+
These instructions are for installing on Ubuntu but they will probably
|
9
|
+
work with minor adjustments on other systems as well.
|
11
10
|
|
12
|
-
|
13
|
-
|
11
|
+
I recommend using RVM (http://beginrescueend.com/). This enables you
|
12
|
+
to safely mess with ruby without messing with the system ruby. Achoo
|
13
|
+
is developed using ruby 1.9.2.
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
- Make sure that you have achoo's non-gem requirements installed:
|
16
|
+
|
17
|
+
sudo aptitude install libxml2 libxml2-dev libxslt1 libxslt1-dev
|
18
|
+
|
19
|
+
- Install RVM
|
20
|
+
|
21
|
+
Need to install some libs required to compile ruby
|
22
|
+
|
23
|
+
sudo aptitude install build-essential libssl-dev libreadline6-dev
|
24
|
+
|
25
|
+
(See http://beginrescueend.com/rvm/install/)
|
26
|
+
|
27
|
+
bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)
|
28
|
+
# ... (follow the instructions for loading rvm into your shell's session)
|
29
|
+
rvm install 1.9.2
|
30
|
+
rvm use 1.9.2 --default
|
17
31
|
|
18
32
|
- Install Achoo
|
19
33
|
|
20
34
|
gem install achoo
|
21
35
|
|
22
|
-
- Make sure that ~/.gem/ruby/1.8/bin is in your PATH environment variable
|
23
|
-
|
24
|
-
if echo $PATH | grep -vq ~/.gem/ruby/1.8/bin; then
|
25
|
-
export PATH=~/.gem/ruby/1.8/bin:$PATH
|
26
|
-
echo 'export PATH=~/.gem/ruby/1.8/bin:$PATH' >> ~/.bashrc
|
27
|
-
fi
|
28
36
|
|
29
37
|
=== TRACKING THE LATEST CHANGES
|
30
38
|
|
@@ -56,11 +64,9 @@ Create ~/.achoo from the following template (YAML) and edit it:
|
|
56
64
|
:url : 'https://example.com/achievo/'
|
57
65
|
:user : 'joe'
|
58
66
|
:password : 'geheim'
|
59
|
-
:vcs_dirs : ["/home/joe/projects"]
|
67
|
+
:vcs_dirs : ["/home/joe/projects"]
|
60
68
|
:ical :
|
61
|
-
- :
|
62
|
-
:port : 443
|
63
|
-
:path : "/joe/Calendar"
|
69
|
+
- :url : "https://foo.example.com/joe/Calendar"
|
64
70
|
:user : "joe"
|
65
71
|
:pass : 'GeHeIm'
|
66
72
|
|
@@ -76,11 +82,9 @@ For more usage information, see
|
|
76
82
|
this[http://oierud.name/~kjellm/bliki/AchooTheAchievoCLI.html] blog
|
77
83
|
post.
|
78
84
|
|
79
|
-
==
|
80
|
-
|
81
|
-
To run the tests you need to install some additional gems:
|
85
|
+
== PLUGINS
|
82
86
|
|
83
|
-
|
87
|
+
FIX
|
84
88
|
|
85
89
|
== BUGS
|
86
90
|
|
@@ -93,4 +97,4 @@ Kjell-Magne Øierud <kjellm AT acm DOT org>
|
|
93
97
|
== LICENSE
|
94
98
|
|
95
99
|
This computer program is distributed under the GPL. Please see the
|
96
|
-
COPYING file.
|
100
|
+
COPYING file part of this distribution.
|
@@ -7,8 +7,7 @@ module Achoo
|
|
7
7
|
|
8
8
|
include Achievo::DateField('date', 'viewdate')
|
9
9
|
|
10
|
-
def initialize
|
11
|
-
@agent = agent
|
10
|
+
def initialize
|
12
11
|
@page = nil
|
13
12
|
end
|
14
13
|
|
@@ -53,7 +52,7 @@ module Achoo
|
|
53
52
|
end
|
54
53
|
|
55
54
|
def set_page_to_view_for_date(view, date)
|
56
|
-
@page ||=
|
55
|
+
@page ||= AGENT.get(RC[:hour_admin_url])
|
57
56
|
|
58
57
|
link = @page.link_with(:text => view.capitalize)
|
59
58
|
@form = @page.form(view)
|
@@ -6,9 +6,8 @@ module Achoo
|
|
6
6
|
|
7
7
|
include Achievo::DateField('date', 'activitydate')
|
8
8
|
|
9
|
-
def initialize
|
10
|
-
@
|
11
|
-
@page = @agent.get(RC[:hour_registration_url])
|
9
|
+
def initialize
|
10
|
+
@page = AGENT.get(RC[:hour_registration_url])
|
12
11
|
@form = @page.form('entryform')
|
13
12
|
|
14
13
|
if @form.nil?
|
@@ -17,7 +16,7 @@ module Achoo
|
|
17
16
|
# most cases.
|
18
17
|
|
19
18
|
# FIX Ugly call to a private method using send()
|
20
|
-
haf = HourAdministrationForm.new
|
19
|
+
haf = HourAdministrationForm.new
|
21
20
|
@page = haf.send(:set_page_to_view_for_date, 'dayview', Date.today)
|
22
21
|
@form = @page.form('entryform')
|
23
22
|
end
|
@@ -75,18 +74,12 @@ module Achoo
|
|
75
74
|
collect_options('billpercent')
|
76
75
|
end
|
77
76
|
|
78
|
-
def collect_options(field_name
|
77
|
+
def collect_options(field_name)
|
79
78
|
@form.field_with(:name => field_name).options.collect do |opt|
|
80
79
|
[opt.value.match(/#{field_name}\.id='(\d+)'/)[1], opt.text]
|
81
80
|
end
|
82
81
|
end
|
83
82
|
|
84
|
-
def billing_options
|
85
|
-
@form.field_with(:name => 'billpercent').options.collect do |opt|
|
86
|
-
[opt.value.match(/billpercent\.id='(\d+)'/)[1], opt.text]
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
83
|
def phases_for_selected_project
|
91
84
|
partial_page = retrieve_project_phases_page
|
92
85
|
page = create_page_from_partial(partial_page)
|
@@ -120,8 +113,12 @@ module Achoo
|
|
120
113
|
end
|
121
114
|
|
122
115
|
def all_projects
|
116
|
+
@@allprojects_cache ||= get_all_projects
|
117
|
+
end
|
118
|
+
|
119
|
+
def get_all_projects
|
123
120
|
puts "Getting project page #1..."
|
124
|
-
projects_page =
|
121
|
+
projects_page = AGENT.get(projects_url)
|
125
122
|
projects = scrape_projects(projects_page)
|
126
123
|
|
127
124
|
i = 2
|
@@ -147,8 +144,8 @@ module Achoo
|
|
147
144
|
printf format, 'phase', @phases_seen[phase]
|
148
145
|
printf format, 'remark', @form.remark
|
149
146
|
printf format, 'hours', @form.time
|
150
|
-
printf format, 'worktime', @form.field_with(:name => 'workperiod').
|
151
|
-
printf format, 'billing', @form.field_with(:name => 'billpercent').
|
147
|
+
printf format, 'worktime', @form.field_with(:name => 'workperiod').selected_options.first.text
|
148
|
+
printf format, 'billing', @form.field_with(:name => 'billpercent').selected_options.first.text
|
152
149
|
|
153
150
|
# @form.fields.each do |field|
|
154
151
|
# printf format, field.name, field.value
|
@@ -184,7 +181,7 @@ module Achoo
|
|
184
181
|
def create_page_from_partial(partial_page)
|
185
182
|
body = "<html><head></head><body><form>#{partial_page.body}</form></body></html>"
|
186
183
|
page = Mechanize::Page.new(nil, {'content-type' => 'text/html; charset=iso-8859-1'},
|
187
|
-
body, nil,
|
184
|
+
body, nil, AGENT)
|
188
185
|
end
|
189
186
|
|
190
187
|
def extract_number_from_projectid(projectid)
|
@@ -6,10 +6,13 @@ module Achoo
|
|
6
6
|
|
7
7
|
include Achievo::DateField('to_date', 'todate')
|
8
8
|
|
9
|
-
def initialize
|
9
|
+
def initialize
|
10
10
|
super
|
11
|
-
@page =
|
11
|
+
@page = AGENT.get(atk_submit_to_url(@page.link_with(:text => 'Select range').href))
|
12
12
|
@form = @page.form('entryform')
|
13
|
+
|
14
|
+
# Need to preselect this for some reason. FIX duplicated in super
|
15
|
+
@form.field_with(:name => 'billpercent').options.first.select
|
13
16
|
end
|
14
17
|
|
15
18
|
def date=(date_range)
|
@@ -4,12 +4,8 @@ module Achoo
|
|
4
4
|
module Achievo
|
5
5
|
class LockMonthForm
|
6
6
|
|
7
|
-
def initialize(agent)
|
8
|
-
@agent = agent
|
9
|
-
end
|
10
|
-
|
11
7
|
def lock_month(period)
|
12
|
-
page =
|
8
|
+
page = AGENT.get(RC[:lock_months_url])
|
13
9
|
@form = page.form('entryform')
|
14
10
|
|
15
11
|
@form.period = period
|
@@ -4,9 +4,9 @@ module Achoo
|
|
4
4
|
module Achievo
|
5
5
|
module LoginForm
|
6
6
|
|
7
|
-
def self.login
|
7
|
+
def self.login
|
8
8
|
puts "Fetching data ..."
|
9
|
-
page =
|
9
|
+
page = AGENT.get(RC[:url])
|
10
10
|
|
11
11
|
return if page.forms.empty? # already logged in
|
12
12
|
|
@@ -15,7 +15,7 @@ module Achoo
|
|
15
15
|
form = page.forms.first
|
16
16
|
form.auth_user = RC[:user]
|
17
17
|
form.auth_pw = RC[:password]
|
18
|
-
page =
|
18
|
+
page = AGENT.submit(form, form.buttons.first)
|
19
19
|
|
20
20
|
if page.body.match(/Username and\/or password are incorrect. Please try again./)
|
21
21
|
raise "Username and/or password are incorrect."
|
data/lib/achoo/app.rb
CHANGED
@@ -4,9 +4,14 @@ require 'achoo/term'
|
|
4
4
|
require 'achoo/ui'
|
5
5
|
require 'logger'
|
6
6
|
require 'mechanize'
|
7
|
-
|
7
|
+
require 'plugman'
|
8
|
+
require 'plugman/finder'
|
8
9
|
|
9
10
|
module Achoo
|
11
|
+
|
12
|
+
AGENT = Mechanize.new
|
13
|
+
PLUGINS = Plugman.new('achoo')
|
14
|
+
|
10
15
|
class App
|
11
16
|
|
12
17
|
include UI::Commands
|
@@ -15,19 +20,22 @@ module Achoo
|
|
15
20
|
|
16
21
|
|
17
22
|
def initialize(log=false)
|
18
|
-
@
|
23
|
+
@last_used_date = Date.today
|
19
24
|
if log
|
20
|
-
|
25
|
+
AGENT.log = Logger.new("achoo_http.log")
|
21
26
|
end
|
22
27
|
end
|
23
28
|
|
24
29
|
|
25
30
|
def start
|
26
31
|
begin
|
32
|
+
PLUGINS.load_plugins
|
33
|
+
puts PLUGINS.log if ENV['ACHOO_DEBUG']
|
34
|
+
PLUGINS.send_at_startup
|
27
35
|
print_welcome
|
28
|
-
warm_up_ical_cache
|
29
36
|
login
|
30
37
|
scrape_urls
|
38
|
+
#print_homescreen
|
31
39
|
command_loop
|
32
40
|
rescue SystemExit => e
|
33
41
|
raise
|
@@ -49,6 +57,8 @@ module Achoo
|
|
49
57
|
while true
|
50
58
|
begin
|
51
59
|
trap("INT", "DEFAULT");
|
60
|
+
PLUGINS.send_before_print_menu(@last_used_date)
|
61
|
+
@last_used_date = Date.today
|
52
62
|
choices = ["Register hours",
|
53
63
|
"Show flexitime balance",
|
54
64
|
"Day hour report",
|
@@ -64,6 +74,7 @@ module Achoo
|
|
64
74
|
dispatch(answer)
|
65
75
|
rescue Interrupt
|
66
76
|
puts # Add a new line in case we are prompting
|
77
|
+
#print_homescreen
|
67
78
|
end
|
68
79
|
end
|
69
80
|
end
|
@@ -74,25 +85,26 @@ module Achoo
|
|
74
85
|
when '0', 'q', 'Q'
|
75
86
|
exit
|
76
87
|
when '1', ''
|
77
|
-
register_hours
|
88
|
+
date = register_hours
|
89
|
+
@last_used_date = date.class == Array ? date.first : date
|
78
90
|
when '2'
|
79
|
-
show_flexi_time
|
91
|
+
show_flexi_time
|
80
92
|
when '3'
|
81
|
-
show_registered_hours_for_day
|
93
|
+
show_registered_hours_for_day
|
82
94
|
when '4'
|
83
|
-
show_registered_hours_for_week
|
95
|
+
show_registered_hours_for_week
|
84
96
|
when '5'
|
85
|
-
show_holiday_report
|
97
|
+
show_holiday_report
|
86
98
|
when '6'
|
87
|
-
lock_month
|
99
|
+
lock_month
|
88
100
|
when '7'
|
89
|
-
view_report
|
101
|
+
view_report
|
90
102
|
end
|
91
103
|
end
|
92
104
|
|
93
105
|
|
94
106
|
def scrape_urls
|
95
|
-
page =
|
107
|
+
page = AGENT.get(AGENT.current_page.frames.find {|f| f.name == 'menu'}.href)
|
96
108
|
menu_links = page.search('a.menuItemLevel2')
|
97
109
|
|
98
110
|
RC[:hour_registration_url] = menu_link_to_url(menu_links, 'Time Registration')
|
@@ -118,7 +130,7 @@ module Achoo
|
|
118
130
|
|
119
131
|
def login
|
120
132
|
load_cookies
|
121
|
-
Achievo::LoginForm.login
|
133
|
+
Achievo::LoginForm.login
|
122
134
|
save_cookies
|
123
135
|
end
|
124
136
|
|
@@ -126,26 +138,13 @@ module Achoo
|
|
126
138
|
def load_cookies
|
127
139
|
cookies_file = "#{ENV['HOME']}/.achoo_cookies.yml"
|
128
140
|
if FileTest.exists? cookies_file
|
129
|
-
|
141
|
+
AGENT.cookie_jar.load(cookies_file)
|
130
142
|
end
|
131
143
|
end
|
132
144
|
|
133
145
|
|
134
146
|
def save_cookies
|
135
|
-
|
136
|
-
end
|
137
|
-
|
138
|
-
|
139
|
-
def warm_up_ical_cache
|
140
|
-
Thread.new do
|
141
|
-
RC[:ical].each do |config|
|
142
|
-
begin
|
143
|
-
ICal.from_http_request(config)
|
144
|
-
rescue Exception => e
|
145
|
-
# Ignore, we are just doing this to populate the cache
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
147
|
+
AGENT.cookie_jar.save_as("#{ENV['HOME']}/.achoo_cookies.yml")
|
149
148
|
end
|
150
149
|
|
151
150
|
end
|
data/lib/achoo/awake.rb
CHANGED
@@ -47,7 +47,7 @@ module Achoo
|
|
47
47
|
else # :awake, :boot
|
48
48
|
# We don't know the end of the session
|
49
49
|
session << Temporal::OpenTimespan.new(g.last.time, g.first.time)
|
50
|
-
g.unshift(System::LogEntry.new(
|
50
|
+
g.unshift(System::LogEntry.new(Time.at(0), :crash))
|
51
51
|
end
|
52
52
|
|
53
53
|
raise "Session must consist of even number of events. Found #{g.length}" unless g.length.even?
|
data/lib/achoo/extensions.rb
CHANGED
data/lib/achoo/ical.rb
CHANGED
@@ -3,6 +3,7 @@ require 'achoo/temporal'
|
|
3
3
|
require 'achoo/ui'
|
4
4
|
require 'net/https'
|
5
5
|
require 'ri_cal'
|
6
|
+
require 'uri'
|
6
7
|
|
7
8
|
module Achoo
|
8
9
|
class ICal
|
@@ -14,13 +15,16 @@ module Achoo
|
|
14
15
|
def self.from_http_request(params)
|
15
16
|
return @@cache[params] if @@cache[params]
|
16
17
|
|
17
|
-
|
18
|
+
url = URI.parse(params[:url])
|
19
|
+
|
20
|
+
http = Net::HTTP.new(url.host, url.port)
|
18
21
|
http.use_ssl = true
|
19
22
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
20
23
|
ics = http.start do |http|
|
21
|
-
request = Net::HTTP::Get.new(
|
24
|
+
request = Net::HTTP::Get.new(url.path)
|
22
25
|
request.basic_auth(params[:user], params[:pass])
|
23
26
|
response = http.request(request)
|
27
|
+
raise response.message unless response.is_a?(Net::HTTPSuccess)
|
24
28
|
response.body
|
25
29
|
end
|
26
30
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'achoo/awake'
|
2
|
+
require 'achoo/ui'
|
3
|
+
|
4
|
+
module Achoo
|
5
|
+
class Plugin
|
6
|
+
class Awake < Plugman::PluginBase
|
7
|
+
|
8
|
+
include UI::ExceptionHandling
|
9
|
+
|
10
|
+
def before_register_hour_hours(date)
|
11
|
+
puts "Awake log:"
|
12
|
+
begin
|
13
|
+
awake = Achoo::Awake.new
|
14
|
+
awake.at(date)
|
15
|
+
puts
|
16
|
+
rescue Exception => e
|
17
|
+
print handle_exception("Failed to retrieve awake log.", e)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'achoo'
|
2
|
+
require 'achoo/ical'
|
3
|
+
require 'achoo/ui'
|
4
|
+
require 'plugman/plugin_base'
|
5
|
+
|
6
|
+
module Achoo
|
7
|
+
class Plugin
|
8
|
+
class Ical < Plugman::PluginBase
|
9
|
+
|
10
|
+
include UI::ExceptionHandling
|
11
|
+
|
12
|
+
def state_ok?; RC.has_key?(:ical); end
|
13
|
+
|
14
|
+
def at_startup
|
15
|
+
warm_up_ical_cache
|
16
|
+
end
|
17
|
+
|
18
|
+
def before_register_hour_remark(date)
|
19
|
+
puts '-' * 80
|
20
|
+
puts "Calendar events for #{date}:"
|
21
|
+
puts '---'
|
22
|
+
begin
|
23
|
+
RC[:ical].each do |config|
|
24
|
+
Achoo::ICal.from_http_request(config).print_events(date)
|
25
|
+
end
|
26
|
+
rescue Exception => e
|
27
|
+
puts handle_exception("Failed to retrieve calendar events.", e)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def warm_up_ical_cache
|
34
|
+
Thread.new do
|
35
|
+
RC[:ical].each do |config|
|
36
|
+
begin
|
37
|
+
Achoo::ICal.from_http_request(config)
|
38
|
+
rescue Exception => e
|
39
|
+
puts "Failed to fetch calendar data: #{e}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|