achoo 0.3 → 0.4.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.
- data/CHANGES +12 -0
- data/README.rdoc +26 -30
- data/Rakefile +3 -0
- data/bin/achoo +2 -2
- data/lib/achoo.rb +1 -139
- data/lib/achoo/achievo.rb +13 -0
- data/lib/achoo/achievo/form.rb +22 -0
- data/lib/achoo/achievo/hour_administration_form.rb +91 -0
- data/lib/achoo/achievo/hour_registration_form.rb +230 -0
- data/lib/achoo/achievo/hour_registration_form_ranged.rb +49 -0
- data/lib/achoo/achievo/lock_month_form.rb +44 -0
- data/lib/achoo/achievo/login_form.rb +27 -0
- data/lib/achoo/achievo/table.rb +30 -0
- data/lib/achoo/app.rb +153 -0
- data/lib/achoo/awake.rb +86 -100
- data/lib/achoo/extensions.rb +24 -0
- data/lib/achoo/ical.rb +47 -40
- data/lib/achoo/rc_loader.rb +42 -42
- data/lib/achoo/system.rb +8 -3
- data/lib/achoo/system/cstruct.rb +67 -0
- data/lib/achoo/system/log_entry.rb +24 -0
- data/lib/achoo/system/pm_suspend.rb +17 -20
- data/lib/achoo/system/utmp_record.rb +64 -0
- data/lib/achoo/system/wtmp.rb +14 -10
- data/lib/achoo/temporal.rb +8 -0
- data/lib/achoo/temporal/open_timespan.rb +16 -0
- data/lib/achoo/temporal/timespan.rb +122 -0
- data/lib/achoo/term.rb +58 -56
- data/lib/achoo/term/menu.rb +2 -2
- data/lib/achoo/term/table.rb +59 -60
- data/lib/achoo/ui.rb +13 -9
- data/lib/achoo/ui/commands.rb +60 -38
- data/lib/achoo/ui/common.rb +10 -7
- data/lib/achoo/ui/date_chooser.rb +69 -65
- data/lib/achoo/ui/date_choosers.rb +15 -14
- data/lib/achoo/ui/exception_handling.rb +14 -12
- data/lib/achoo/ui/month_chooser.rb +37 -24
- data/lib/achoo/ui/optionally_ranged_date_chooser.rb +29 -25
- data/lib/achoo/ui/register_hours.rb +116 -114
- data/lib/achoo/vcs.rb +32 -30
- data/lib/achoo/vcs/git.rb +18 -14
- data/lib/achoo/vcs/subversion.rb +25 -23
- metadata +30 -24
- data/lib/achoo/binary.rb +0 -7
- data/lib/achoo/binary/cstruct.rb +0 -60
- data/lib/achoo/binary/utmp_record.rb +0 -59
- data/lib/achoo/form.rb +0 -18
- data/lib/achoo/hour_administration_form.rb +0 -131
- data/lib/achoo/hour_registration_form.rb +0 -227
- data/lib/achoo/hour_registration_form_ranged.rb +0 -45
- data/lib/achoo/lock_month_form.rb +0 -40
- data/lib/achoo/open_timespan.rb +0 -13
- data/lib/achoo/timespan.rb +0 -119
data/CHANGES
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
2010-04-20: version 0.4.1
|
2
|
+
|
3
|
+
- Bug fixes
|
4
|
+
|
5
|
+
2010-04-20: version 0.4
|
6
|
+
|
7
|
+
- Converted rc file format to YAML
|
8
|
+
|
9
|
+
- Prefetch and cache iCalendar data in a parallel thread at startup
|
10
|
+
|
11
|
+
- Added support for 'Time Survey' reports
|
12
|
+
|
1
13
|
2010-04-05: version 0.3
|
2
14
|
|
3
15
|
- More compact time span format in awake log
|
data/README.rdoc
CHANGED
@@ -9,18 +9,15 @@ These instructions are for installing on Ubuntu 9.10 (Karmic Koala),
|
|
9
9
|
but they will probably work with minor adjustments on other systems as
|
10
10
|
well.
|
11
11
|
|
12
|
-
- Make sure that you have ruby and rubygems installed
|
12
|
+
- Make sure that you have ruby and rubygems installed together with
|
13
|
+
achoo's non-gem requirements:
|
13
14
|
|
14
|
-
sudo aptitude install ruby rubygems
|
15
|
+
sudo aptitude install ruby rubygems ruby1.8-dev libxml2 \
|
16
|
+
libxml2-dev libxslt1 libxslt1-dev libopenssl-ruby
|
15
17
|
|
16
|
-
- Install
|
18
|
+
- Install Achoo
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
- Download achoo-0.2.gem[http://github.com/downloads/kjellm/achoo/achoo-0.2.gem] and install it
|
21
|
-
|
22
|
-
wget http://github.com/downloads/kjellm/achoo/achoo-0.2.gem
|
23
|
-
gem install achoo-0.2.gem
|
20
|
+
gem install achoo
|
24
21
|
|
25
22
|
- Make sure that ~/.gem/ruby/1.8/bin is in your PATH environment variable
|
26
23
|
|
@@ -31,9 +28,9 @@ well.
|
|
31
28
|
|
32
29
|
=== TRACKING THE LATEST CHANGES
|
33
30
|
|
34
|
-
Requires git
|
31
|
+
Requires git
|
35
32
|
|
36
|
-
sudo aptitude install
|
33
|
+
sudo aptitude install git-core
|
37
34
|
|
38
35
|
Then
|
39
36
|
|
@@ -45,30 +42,28 @@ Or if you already has cloned achoo, update with
|
|
45
42
|
|
46
43
|
Generate gem and install it
|
47
44
|
|
48
|
-
|
49
|
-
gem install
|
45
|
+
gem build achoo.gemspec
|
46
|
+
gem install achoo-XXX.gem
|
50
47
|
|
51
48
|
== USAGE
|
52
49
|
|
53
50
|
First, make sure that language in Achievo's user preferences is
|
54
51
|
English and theme is 'no value'.
|
55
52
|
|
56
|
-
Create ~/.achoo from the following template and edit it:
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
}
|
71
|
-
|
53
|
+
Create ~/.achoo from the following template (YAML) and edit it:
|
54
|
+
|
55
|
+
---
|
56
|
+
:url : 'https://example.com/achievo/'
|
57
|
+
:user : 'joe'
|
58
|
+
:password : 'geheim'
|
59
|
+
:vcs_dirs : ["/home/joe/projects"],
|
60
|
+
:ical :
|
61
|
+
- :host : "foo.example.com"
|
62
|
+
:port : 443
|
63
|
+
:path : "/joe/Calendar"
|
64
|
+
:user : "joe"
|
65
|
+
:pass : 'GeHeIm'
|
66
|
+
|
72
67
|
Then
|
73
68
|
|
74
69
|
chmod 0600 ~/.achoo
|
@@ -78,7 +73,8 @@ You can then run achoo from a shell with the achoo command
|
|
78
73
|
achoo
|
79
74
|
|
80
75
|
For more usage information, see
|
81
|
-
this[http://oierud.name/~kjellm/bliki/AchooTheAchievoCLI.html] blog
|
76
|
+
this[http://oierud.name/~kjellm/bliki/AchooTheAchievoCLI.html] blog
|
77
|
+
post.
|
82
78
|
|
83
79
|
== SET UP DEVELOPMENT ENVIRONMENT
|
84
80
|
|
data/Rakefile
CHANGED
data/bin/achoo
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require 'achoo'
|
3
|
+
require 'achoo/app'
|
4
4
|
require 'achoo/rc_loader'
|
5
5
|
require 'optparse'
|
6
6
|
|
@@ -18,7 +18,7 @@ def main
|
|
18
18
|
|
19
19
|
load_rc(options[:rc_file])
|
20
20
|
|
21
|
-
achoo = Achoo.new(options[:log])
|
21
|
+
achoo = Achoo::App.new(options[:log])
|
22
22
|
achoo.start
|
23
23
|
end
|
24
24
|
|
data/lib/achoo.rb
CHANGED
@@ -1,140 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'achoo/term'
|
4
|
-
require 'achoo/ui'
|
5
|
-
require 'logger'
|
6
|
-
require 'mechanize'
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
class Achoo
|
11
|
-
|
12
|
-
include Achoo::UI::Commands
|
13
|
-
include Achoo::UI::ExceptionHandling
|
14
|
-
include Achoo::UI::RegisterHours
|
15
|
-
|
16
|
-
def initialize(log=false)
|
17
|
-
@agent = Mechanize.new
|
18
|
-
if log
|
19
|
-
@agent.log = Logger.new("achoo_http.log")
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def start
|
24
|
-
begin
|
25
|
-
print_welcome
|
26
|
-
login
|
27
|
-
scrape_urls
|
28
|
-
command_loop
|
29
|
-
rescue SystemExit => e
|
30
|
-
raise
|
31
|
-
rescue Exception => e
|
32
|
-
handle_fatal_exception("Something bad happened. Shutting down.", e)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
|
37
|
-
def print_welcome
|
38
|
-
puts Term.shadowbox("Welcome to Achoo!")
|
39
|
-
end
|
40
|
-
|
41
|
-
|
42
|
-
def command_loop
|
43
|
-
while true
|
44
|
-
begin
|
45
|
-
trap("INT", "DEFAULT");
|
46
|
-
answer = Term.choose('[1]',
|
47
|
-
["Register hours",
|
48
|
-
"Show flexitime balance",
|
49
|
-
"Day hour report",
|
50
|
-
"Week hour report",
|
51
|
-
"Holiday balance",
|
52
|
-
"Lock month",
|
53
|
-
],
|
54
|
-
"Exit",
|
55
|
-
['q', 'Q', ''])
|
56
|
-
dispatch(answer)
|
57
|
-
rescue Interrupt
|
58
|
-
puts # Add a new line in case we are prompting
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
|
64
|
-
def dispatch(command)
|
65
|
-
case command
|
66
|
-
when '0', 'q', 'Q'
|
67
|
-
exit
|
68
|
-
when '1', ''
|
69
|
-
register_hours(@agent)
|
70
|
-
when '2'
|
71
|
-
show_flexi_time(@agent)
|
72
|
-
when '3'
|
73
|
-
show_registered_hours_for_day(@agent)
|
74
|
-
when '4'
|
75
|
-
show_registered_hours_for_week(@agent)
|
76
|
-
when '5'
|
77
|
-
show_holiday_report(@agent)
|
78
|
-
when '6'
|
79
|
-
lock_month(@agent)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
|
84
|
-
def scrape_urls
|
85
|
-
page = @agent.get(@agent.current_page.frames.find {|f| f.name == 'menu'}.href)
|
86
|
-
menu_links = page.search('a.menuItemLevel2')
|
87
|
-
|
88
|
-
RC[:hour_registration_url] = menu_link_to_url(menu_links, 'Time Registration')
|
89
|
-
RC[:lock_months_url] = menu_link_to_url(menu_links, 'Lock months')
|
90
|
-
RC[:holiday_report_url] = menu_link_to_url(menu_links, 'Holiday report')
|
91
|
-
RC[:hour_admin_url] = RC[:hour_registration_url]
|
92
|
-
end
|
93
|
-
|
94
|
-
def menu_link_to_url(menu_links, text)
|
95
|
-
a_tag = menu_links.find {|a|
|
96
|
-
a.text.strip == text
|
97
|
-
}
|
98
|
-
|
99
|
-
if a_tag.nil?
|
100
|
-
raise Exception.new("Could not find the '#{text}' link in Achievo.\nMake sure that language is 'English' and theme is 'no value' in Achievo's user preferences.\nYou must delete ~/.achoo_cookies.yml for these changes to take affect.")
|
101
|
-
end
|
102
|
-
|
103
|
-
url = a_tag.attribute('onclick').value.match(/window\.open\('([^']+)/)[1]
|
104
|
-
return "#{RC[:url]}#{url}"
|
105
|
-
end
|
106
|
-
|
107
|
-
|
108
|
-
def login
|
109
|
-
load_cookies
|
110
|
-
|
111
|
-
puts "Fetching data ..."
|
112
|
-
page = @agent.get(RC[:url])
|
113
|
-
|
114
|
-
return if page.forms.empty?
|
115
|
-
|
116
|
-
puts "Logging in ..."
|
117
|
-
|
118
|
-
form = page.forms.first
|
119
|
-
form.auth_user = RC[:user]
|
120
|
-
form.auth_pw = RC[:password]
|
121
|
-
page = @agent.submit(form, form.buttons.first)
|
122
|
-
|
123
|
-
if page.body.match(/Username and\/or password are incorrect. Please try again./)
|
124
|
-
raise "Username and/or password are incorrect."
|
125
|
-
end
|
126
|
-
|
127
|
-
@agent.cookie_jar.save_as("#{ENV['HOME']}/.achoo_cookies.yml")
|
128
|
-
end
|
129
|
-
|
130
|
-
|
131
|
-
def load_cookies
|
132
|
-
cookies_file = "#{ENV['HOME']}/.achoo_cookies.yml"
|
133
|
-
if FileTest.exists? cookies_file
|
134
|
-
@agent.cookie_jar.load(cookies_file)
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
|
1
|
+
module Achoo
|
139
2
|
end
|
140
|
-
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'achoo'
|
2
|
+
|
3
|
+
module Achoo
|
4
|
+
module Achievo
|
5
|
+
autoload :Form, 'achoo/achievo/form.rb'
|
6
|
+
autoload :HourAdministrationForm, 'achoo/achievo/hour_administration_form.rb'
|
7
|
+
autoload :HourRegistrationForm, 'achoo/achievo/hour_registration_form.rb'
|
8
|
+
autoload :HourRegistrationFormRanged, 'achoo/achievo/hour_registration_form_ranged.rb'
|
9
|
+
autoload :LockMonthForm, 'achoo/achievo/lock_month_form.rb'
|
10
|
+
autoload :LoginForm, 'achoo/achievo/login_form.rb'
|
11
|
+
autoload :Table, 'achoo/achievo/table.rb'
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'achoo/achievo'
|
2
|
+
|
3
|
+
module Achoo
|
4
|
+
module Achievo
|
5
|
+
class Form
|
6
|
+
|
7
|
+
def date=(date)
|
8
|
+
# Day and month must be prefixed with '0' if single
|
9
|
+
# digit. Date.day and Date.month doesn't do this. Use strftime
|
10
|
+
day_field.value = date.strftime('%d')
|
11
|
+
month_field.value = date.strftime('%m')
|
12
|
+
year_field.value = date.year
|
13
|
+
end
|
14
|
+
|
15
|
+
def date
|
16
|
+
Date.new(year_field.value.to_i, month_field.value.to_i,
|
17
|
+
day_field.value.to_i)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'achoo/achievo'
|
2
|
+
require 'achoo/term/table'
|
3
|
+
|
4
|
+
module Achoo
|
5
|
+
module Achievo
|
6
|
+
class HourAdministrationForm < Form
|
7
|
+
|
8
|
+
def initialize(agent)
|
9
|
+
@agent = agent
|
10
|
+
@page = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def show_registered_hours_for_day(date)
|
14
|
+
show_registered_hours(date, 'dayview', '#rl_1 tr')
|
15
|
+
end
|
16
|
+
|
17
|
+
def show_registered_hours_for_week(date)
|
18
|
+
show_registered_hours(date, 'weekview', '//form[@name="weekview"]/following::table/tr')
|
19
|
+
end
|
20
|
+
|
21
|
+
def flexi_time(date)
|
22
|
+
set_page_to_view_for_date('dayview', date)
|
23
|
+
|
24
|
+
@page.body.match(/Flexi time balance: (-?\d+:\d+)/)[1]
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def show_registered_hours(date, view, query)
|
30
|
+
set_page_to_view_for_date(view, date)
|
31
|
+
|
32
|
+
table = Table.new(@page.search(query))
|
33
|
+
|
34
|
+
if view == 'weekview'
|
35
|
+
table.first.each {|c| c.gsub!(/\s+/, ' ') }
|
36
|
+
end
|
37
|
+
|
38
|
+
if view == 'dayview'
|
39
|
+
table.select_columns do |c|
|
40
|
+
# '' -> Ruby 1.9, ' ' -> Ruby 1.8
|
41
|
+
!['', ' ', 'Billing billed', 'Billing marked', 'Billing total'].include?(c[0])
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
summaries = table.length > 1 ? table.last : nil
|
47
|
+
|
48
|
+
Term::Table.new(table.first,
|
49
|
+
table[1 .. table.length-2],
|
50
|
+
summaries).print
|
51
|
+
end
|
52
|
+
|
53
|
+
def set_page_to_view_for_date(view, date)
|
54
|
+
@page ||= @agent.get(RC[:hour_admin_url])
|
55
|
+
|
56
|
+
link = @page.link_with(:text => view.capitalize)
|
57
|
+
@form = @page.form(view)
|
58
|
+
unless link.nil?
|
59
|
+
puts "Fetching #{view} ..."
|
60
|
+
@page = link.click
|
61
|
+
@form = @page.form(view)
|
62
|
+
end
|
63
|
+
unless date == self.date
|
64
|
+
@page = get_page_for(date)
|
65
|
+
@form = @page.form(view)
|
66
|
+
end
|
67
|
+
|
68
|
+
@page
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_page_for(date)
|
72
|
+
puts "Fetching data for #{date} ..."
|
73
|
+
self.date = date
|
74
|
+
@page = @form.submit
|
75
|
+
end
|
76
|
+
|
77
|
+
def day_field
|
78
|
+
@form.field_with(:name => 'viewdate[day]')
|
79
|
+
end
|
80
|
+
|
81
|
+
def month_field
|
82
|
+
@form.field_with(:name => 'viewdate[month]')
|
83
|
+
end
|
84
|
+
|
85
|
+
def year_field
|
86
|
+
@form.field_with(:name => 'viewdate[year]')
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,230 @@
|
|
1
|
+
require 'achoo/achievo'
|
2
|
+
|
3
|
+
module Achoo
|
4
|
+
module Achievo
|
5
|
+
class HourRegistrationForm < Form
|
6
|
+
|
7
|
+
def initialize(agent)
|
8
|
+
@agent = agent
|
9
|
+
@page = @agent.get(RC[:hour_registration_url])
|
10
|
+
@form = @page.form('entryform')
|
11
|
+
|
12
|
+
if @form.nil?
|
13
|
+
# Happens if the user has viewed a day or week report for a
|
14
|
+
# locked month. Fetching todays day report should fix this in
|
15
|
+
# most cases.
|
16
|
+
|
17
|
+
# FIX Ugly call to a private method using send()
|
18
|
+
haf = HourAdministrationForm.new(@agent)
|
19
|
+
@page = haf.send(:set_page_to_view_for_date, 'dayview', Date.today)
|
20
|
+
@form = @page.form('entryform')
|
21
|
+
end
|
22
|
+
|
23
|
+
if @form.nil?
|
24
|
+
raise "Failed to retrieve the hour registration form.\nThe likely cause is that you have locked the current month, which is a silly thing to do."
|
25
|
+
end
|
26
|
+
|
27
|
+
@projects_seen = {}
|
28
|
+
@phases_seen = {}
|
29
|
+
|
30
|
+
# Need to preselect this for some reason
|
31
|
+
@form.field_with(:name => 'billpercent').options.first.select
|
32
|
+
# Preselecting this one as well, just in case
|
33
|
+
@form.field_with(:name => 'workperiod').options.first.select
|
34
|
+
end
|
35
|
+
|
36
|
+
def project
|
37
|
+
extract_number_from_projectid(@form.projectid)
|
38
|
+
end
|
39
|
+
|
40
|
+
def project=(projectid)
|
41
|
+
@form.projectid = "project.id='#{projectid}'"
|
42
|
+
end
|
43
|
+
|
44
|
+
def remark=(remark)
|
45
|
+
@form.remark = remark
|
46
|
+
end
|
47
|
+
|
48
|
+
def hours=(hours)
|
49
|
+
@form.time = hours
|
50
|
+
end
|
51
|
+
|
52
|
+
def phase
|
53
|
+
@form.phaseid.match(/phase\.id='(\d+)'/)[1]
|
54
|
+
end
|
55
|
+
|
56
|
+
def phase=(phaseid)
|
57
|
+
@form.phaseid = "phase.id='#{phaseid}'"
|
58
|
+
end
|
59
|
+
|
60
|
+
def workperiod=(workperiod)
|
61
|
+
@form.workperiod = "workperiod.id='#{workperiod}'"
|
62
|
+
end
|
63
|
+
|
64
|
+
def billing=(billing)
|
65
|
+
@form.billpercent = "billpercent.id='#{billing}'"
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
def worktime_periods
|
70
|
+
@form.field_with(:name => 'workperiod').options.collect do |opt|
|
71
|
+
[opt.value.match(/workperiod\.id='(\d+)'/)[1], opt.text]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def billing_options
|
76
|
+
@form.field_with(:name => 'billpercent').options.collect do |opt|
|
77
|
+
[opt.value.match(/billpercent\.id='(\d+)'/)[1], opt.text]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def phases_for_selected_project
|
82
|
+
partial_page = retrieve_project_phases_page
|
83
|
+
page = create_page_from_partial(partial_page)
|
84
|
+
field = page.forms.first.field_with(:name => 'phaseid')
|
85
|
+
|
86
|
+
phases = []
|
87
|
+
if field.respond_to?(:options)
|
88
|
+
field.options.each do |opt|
|
89
|
+
phases << [extract_number_from_phaseid(opt.value), opt.text]
|
90
|
+
end
|
91
|
+
else
|
92
|
+
partial_page.body.match(/(^[^<]+) </)
|
93
|
+
phases << [extract_number_from_phaseid(field.value), $1]
|
94
|
+
end
|
95
|
+
|
96
|
+
phases.each {|p| @phases_seen[p[0]] = p[1]}
|
97
|
+
|
98
|
+
return phases
|
99
|
+
end
|
100
|
+
|
101
|
+
def recent_projects
|
102
|
+
projects = []
|
103
|
+
@form.field_with(:name => 'projectid').options.each do |opt|
|
104
|
+
val = opt.value["project.id='".length..-2]
|
105
|
+
projects << [val, opt.text]
|
106
|
+
end
|
107
|
+
|
108
|
+
projects.each {|p| @projects_seen[p[0]] = p[1]}
|
109
|
+
|
110
|
+
projects
|
111
|
+
end
|
112
|
+
|
113
|
+
def all_projects
|
114
|
+
puts "Getting project page #1..."
|
115
|
+
projects_page = @agent.get(projects_url)
|
116
|
+
projects = scrape_projects(projects_page)
|
117
|
+
|
118
|
+
i = 2
|
119
|
+
while (link = projects_page.link_with(:text => 'Next'))
|
120
|
+
puts "Getting project page ##{i}..."
|
121
|
+
projects_page = link.click
|
122
|
+
projects.merge!(scrape_projects(projects_page))
|
123
|
+
i += 1
|
124
|
+
end
|
125
|
+
|
126
|
+
projects.keys.sort.collect do |name|
|
127
|
+
id = projects[name][0]
|
128
|
+
text = "#{projects[name][1]}: #{name}"
|
129
|
+
@projects_seen[id] = text
|
130
|
+
[id, text]
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def print_values
|
135
|
+
format = "%10s: \"%s\"\n"
|
136
|
+
printf format, 'date', date_to_s
|
137
|
+
printf format, 'project', @projects_seen[project]
|
138
|
+
printf format, 'phase', @phases_seen[phase]
|
139
|
+
printf format, 'remark', @form.remark
|
140
|
+
printf format, 'hours', @form.time
|
141
|
+
printf format, 'worktime', @form.field_with(:name => 'workperiod').options.first.text
|
142
|
+
printf format, 'billing', @form.field_with(:name => 'billpercent').options.first.text
|
143
|
+
|
144
|
+
# @form.fields.each do |field|
|
145
|
+
# printf format, field.name, field.value
|
146
|
+
# end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
def submit
|
151
|
+
@form.submit()
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
|
156
|
+
def date_to_s
|
157
|
+
date.strftime("%Y-%m-%d")
|
158
|
+
end
|
159
|
+
|
160
|
+
def retrieve_project_phases_page
|
161
|
+
old = {
|
162
|
+
:atkaction => @form.atkaction,
|
163
|
+
:action => @form.action,
|
164
|
+
}
|
165
|
+
|
166
|
+
@form.action = RC[:url]+"/dispatch.php?atkpartial=attribute.phaseid.refresh"
|
167
|
+
@form.atkaction = 'add'
|
168
|
+
partial_page = @form.submit
|
169
|
+
@form.action = old[:action]
|
170
|
+
@form.atkaction = old[:atkaction]
|
171
|
+
|
172
|
+
return partial_page
|
173
|
+
end
|
174
|
+
|
175
|
+
def create_page_from_partial(partial_page)
|
176
|
+
body = "<html><head></head><body><form>#{partial_page.body}</form></body></html>"
|
177
|
+
page = Mechanize::Page.new(nil, {'content-type' => 'text/html; charset=iso-8859-1'},
|
178
|
+
body, nil, @agent)
|
179
|
+
end
|
180
|
+
|
181
|
+
def day_field
|
182
|
+
@form.field_with(:name => 'activitydate[day]')
|
183
|
+
end
|
184
|
+
|
185
|
+
def month_field
|
186
|
+
@form.field_with(:name => 'activitydate[month]')
|
187
|
+
end
|
188
|
+
|
189
|
+
def year_field
|
190
|
+
@form.field_with(:name => 'activitydate[year]')
|
191
|
+
end
|
192
|
+
|
193
|
+
def extract_number_from_projectid(projectid)
|
194
|
+
projectid.match(/project\.id='(\d+)'/)[1]
|
195
|
+
end
|
196
|
+
|
197
|
+
def extract_number_from_phaseid(projectid)
|
198
|
+
projectid.match(/phase\.id='(\d+)'/)[1]
|
199
|
+
end
|
200
|
+
|
201
|
+
def projects_url
|
202
|
+
atk_submit_to_url(@page.link_with(:text => 'Select project').href)
|
203
|
+
end
|
204
|
+
|
205
|
+
def atk_submit_to_url(atk_submit)
|
206
|
+
href = atk_submit['javascript:atkSubmit("__'.length..-3]
|
207
|
+
href.gsub!('_13F', '?')
|
208
|
+
href.gsub!('_13D', '=')
|
209
|
+
href.gsub!('_126', '&')
|
210
|
+
href.gsub!('_125', '%')
|
211
|
+
return RC[:url] + '/' + href
|
212
|
+
end
|
213
|
+
|
214
|
+
def scrape_projects(projects_page)
|
215
|
+
projects = {}
|
216
|
+
projects_page.search('table#rl_1 tr').each do |tr|
|
217
|
+
cells = tr.search('td')
|
218
|
+
next if cells.empty?
|
219
|
+
projects[cells[1].text.strip] = [
|
220
|
+
cells[1].at_css('a').attribute('href').to_s.match('project.id%3D%27(\d+)%27')[1],
|
221
|
+
cells[0].text.strip,
|
222
|
+
]
|
223
|
+
end
|
224
|
+
|
225
|
+
return projects
|
226
|
+
end
|
227
|
+
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|