achoo 0.4.2 → 0.5
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.
- 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
|