achoo 0.4.2 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/CHANGES +13 -0
  2. data/README.rdoc +26 -22
  3. data/lib/achoo/achievo/hour_administration_form.rb +2 -3
  4. data/lib/achoo/achievo/hour_registration_form.rb +12 -15
  5. data/lib/achoo/achievo/hour_registration_form_ranged.rb +5 -2
  6. data/lib/achoo/achievo/lock_month_form.rb +1 -5
  7. data/lib/achoo/achievo/login_form.rb +3 -3
  8. data/lib/achoo/app.rb +27 -28
  9. data/lib/achoo/awake.rb +1 -1
  10. data/lib/achoo/extensions.rb +4 -0
  11. data/lib/achoo/ical.rb +6 -2
  12. data/lib/achoo/plugin/awake.rb +23 -0
  13. data/lib/achoo/plugin/ical.rb +47 -0
  14. data/lib/achoo/plugin/vcs.rb +26 -0
  15. data/lib/achoo/plugin_base.rb +6 -0
  16. data/lib/achoo/rc_loader.rb +9 -0
  17. data/lib/achoo/temporal/timespan.rb +3 -3
  18. data/lib/achoo/term.rb +7 -3
  19. data/lib/achoo/term/table.rb +5 -6
  20. data/lib/achoo/ui/commands.rb +12 -12
  21. data/lib/achoo/ui/date_chooser.rb +1 -1
  22. data/lib/achoo/ui/exception_handling.rb +1 -1
  23. data/lib/achoo/ui/register_hours.rb +50 -50
  24. data/lib/achoo/vcs/git.rb +5 -3
  25. data/test/acceptance/test_flexi_time.rb +41 -0
  26. data/test/acceptance/test_lock_month.rb +39 -0
  27. data/test/acceptance/test_register_hours.rb +161 -0
  28. data/test/lib/achievo_mock.rb +76 -0
  29. data/test/lib/achoo_runner.rb +54 -0
  30. data/test/lib/test_helpers.rb +43 -0
  31. data/test/unit/test_achievo_date_field.rb +34 -0
  32. data/test/unit/test_awake.rb +98 -0
  33. data/test/unit/test_extensions_array.rb +25 -0
  34. data/test/unit/test_system_cstruct.rb +28 -0
  35. data/test/unit/test_system_log_entry.rb +31 -0
  36. data/test/unit/test_term_menu.rb +71 -0
  37. data/test/unit/test_term_table.rb +52 -0
  38. data/test/unit/test_timespan.rb +48 -0
  39. data/test/unit/test_ui_date_chooser.rb +36 -0
  40. 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 (Karmic Koala),
9
- but they will probably work with minor adjustments on other systems as
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
- - Make sure that you have ruby and rubygems installed together with
13
- achoo's non-gem requirements:
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
- sudo aptitude install ruby rubygems ruby1.8-dev libxml2 \
16
- libxml2-dev libxslt1 libxslt1-dev libopenssl-ruby
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
- - :host : "foo.example.com"
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
- == SET UP DEVELOPMENT ENVIRONMENT
80
-
81
- To run the tests you need to install some additional gems:
85
+ == PLUGINS
82
86
 
83
- rake setup
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(agent)
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 ||= @agent.get(RC[:hour_admin_url])
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(agent)
10
- @agent = agent
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(@agent)
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, pattern)
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 = @agent.get(projects_url)
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').options.first.text
151
- printf format, 'billing', @form.field_with(:name => 'billpercent').options.first.text
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, @agent)
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(agent)
9
+ def initialize
10
10
  super
11
- @page = @agent.get(atk_submit_to_url(@page.link_with(:text => 'Select range').href))
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 = @agent.get(RC[:lock_months_url])
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(agent)
7
+ def self.login
8
8
  puts "Fetching data ..."
9
- page = agent.get(RC[:url])
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 = agent.submit(form, form.buttons.first)
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
- @agent = Mechanize.new
23
+ @last_used_date = Date.today
19
24
  if log
20
- @agent.log = Logger.new("achoo_http.log")
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(@agent)
88
+ date = register_hours
89
+ @last_used_date = date.class == Array ? date.first : date
78
90
  when '2'
79
- show_flexi_time(@agent)
91
+ show_flexi_time
80
92
  when '3'
81
- show_registered_hours_for_day(@agent)
93
+ show_registered_hours_for_day
82
94
  when '4'
83
- show_registered_hours_for_week(@agent)
95
+ show_registered_hours_for_week
84
96
  when '5'
85
- show_holiday_report(@agent)
97
+ show_holiday_report
86
98
  when '6'
87
- lock_month(@agent)
99
+ lock_month
88
100
  when '7'
89
- view_report(@agent)
101
+ view_report
90
102
  end
91
103
  end
92
104
 
93
105
 
94
106
  def scrape_urls
95
- page = @agent.get(@agent.current_page.frames.find {|f| f.name == 'menu'}.href)
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(@agent)
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
- @agent.cookie_jar.load(cookies_file)
141
+ AGENT.cookie_jar.load(cookies_file)
130
142
  end
131
143
  end
132
144
 
133
145
 
134
146
  def save_cookies
135
- @agent.cookie_jar.save_as("#{ENV['HOME']}/.achoo_cookies.yml")
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(-1, :crash))
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?
@@ -45,3 +45,7 @@ class Integer
45
45
  alias minutes minute
46
46
 
47
47
  end
48
+
49
+ if RUBY_VERSION < "1.9"
50
+ Range.send(:alias_method, :cover?, :include?)
51
+ end
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
- http = Net::HTTP.new(params[:host], params[:port])
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(params[:path])
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