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.
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