backlog 0.36.2 → 0.37.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.
Files changed (250) hide show
  1. data/Gemfile +16 -4
  2. data/Gemfile.lock +130 -0
  3. data/History.txt +17 -0
  4. data/README.txt +0 -2
  5. data/Rakefile +17 -7
  6. data/app/controllers/absences_controller.rb +1 -2
  7. data/app/controllers/application_controller.rb +13 -14
  8. data/app/controllers/application_controller.rb.rails2 +186 -0
  9. data/app/controllers/estimates_controller.rb +1 -1
  10. data/app/controllers/groups_controller.rb +3 -1
  11. data/app/controllers/periods_controller.rb +61 -50
  12. data/app/controllers/{backlogs_controller.rb → projects_controller.rb} +35 -35
  13. data/app/controllers/search_controller.rb +2 -2
  14. data/app/controllers/tasks_controller.rb +11 -11
  15. data/app/controllers/user_controller.rb +6 -4
  16. data/app/controllers/welcome_controller.rb +4 -4
  17. data/app/controllers/work_locks_controller.rb +2 -2
  18. data/app/controllers/works_controller.rb +31 -31
  19. data/app/helpers/application_helper.rb +2 -2
  20. data/app/helpers/application_helper.rb.rails2 +118 -0
  21. data/app/helpers/periods_helper.rb +3 -3
  22. data/app/helpers/{backlogs_helper.rb → projects_helper.rb} +5 -5
  23. data/app/helpers/user_helper.rb +2 -2
  24. data/app/{models → mailers}/user_notify.rb +1 -0
  25. data/app/models/absence.rb +2 -2
  26. data/{lib → app/models}/clock.rb +0 -0
  27. data/app/models/estimate.rb +2 -2
  28. data/app/models/party.rb +1 -2
  29. data/app/models/period.rb +17 -18
  30. data/app/models/{backlog.rb → project.rb} +2 -2
  31. data/app/models/sidebar.rb +2 -2
  32. data/app/models/task.rb +28 -28
  33. data/app/models/user.rb +5 -4
  34. data/app/models/work.rb +29 -23
  35. data/app/models/work_lock_nagger.rb +1 -1
  36. data/app/models/works_report_filter.rb +4 -4
  37. data/app/views/customers/_name_list.rhtml +1 -1
  38. data/app/views/layouts/_headers.rhtml +2 -1
  39. data/app/views/layouts/_left_top.rhtml +32 -29
  40. data/app/views/layouts/_shortcuts.rhtml +15 -9
  41. data/app/views/layouts/_shortcuts_js.rhtml +4 -4
  42. data/app/views/layouts/mwrt002.html.erb +44 -0
  43. data/app/views/periods/_burn_down_chart.rhtml +1 -1
  44. data/app/views/periods/_show_active.rhtml +3 -3
  45. data/app/views/periods/_title.rhtml +1 -1
  46. data/app/views/{backlogs → projects}/_buttons.rhtml +4 -4
  47. data/app/views/projects/_form.rhtml +44 -0
  48. data/app/views/projects/_name_list.rhtml +5 -0
  49. data/app/views/projects/edit.rhtml +14 -0
  50. data/app/views/{backlogs → projects}/finish_task.rjs +0 -0
  51. data/app/views/projects/list.rhtml +16 -0
  52. data/app/views/{backlogs → projects}/move_task_to_period.rjs +0 -0
  53. data/app/views/{backlogs → projects}/new.rhtml +1 -1
  54. data/app/views/{backlogs → projects}/reopen_task.rjs +0 -0
  55. data/app/views/{backlogs → projects}/show.rhtml +6 -6
  56. data/app/views/search/results.rhtml +3 -3
  57. data/app/views/tasks/_backlog_header.rhtml +4 -4
  58. data/app/views/tasks/_completed.rhtml +2 -2
  59. data/app/views/tasks/_form.rhtml +13 -13
  60. data/app/views/tasks/_task.rhtml +10 -10
  61. data/app/views/tasks/edit.rhtml +1 -1
  62. data/app/views/tasks/list.rhtml +3 -3
  63. data/app/views/tasks/list_started.rhtml +4 -4
  64. data/app/views/tasks/start_work.rjs +1 -1
  65. data/app/views/user/login.rhtml +1 -1
  66. data/app/views/user/signup.rhtml +1 -1
  67. data/app/views/user/welcome.rhtml +1 -1
  68. data/app/views/works/_description_list.rhtml +1 -1
  69. data/app/views/works/_form.rhtml +5 -5
  70. data/app/views/works/_new_row.rhtml +8 -8
  71. data/app/views/works/_row.rhtml +1 -1
  72. data/app/views/works/_task_id_list.rhtml +1 -1
  73. data/app/views/works/daily_work_sheet.rhtml +1 -1
  74. data/app/views/works/list.rhtml +5 -5
  75. data/app/views/works/list_excel.rhtml +2 -2
  76. data/app/views/works/timeliste.rhtml +14 -14
  77. data/app/views/works/weekly_work_sheet.rhtml +5 -5
  78. data/app/views/works/weekly_work_sheet_details.rhtml +5 -5
  79. data/backlog.gemspec +44 -0
  80. data/bin/backlog +5 -1
  81. data/config.ru +4 -0
  82. data/config/application.rb +10 -0
  83. data/config/boot.rb +12 -116
  84. data/config/database.yml +3 -6
  85. data/config/database.yml~ +17 -0
  86. data/config/environment.rb +28 -49
  87. data/config/environments/development.rb +24 -20
  88. data/config/environments/development.rb.rails2 +26 -0
  89. data/config/environments/production.rb +26 -22
  90. data/config/environments/test.rb +20 -15
  91. data/config/environments/user_environment.rb +1 -1
  92. data/config/initializers/backtrace_silencers.rb +7 -0
  93. data/config/initializers/inflections.rb +10 -0
  94. data/config/initializers/jdbc.rb +1 -1
  95. data/config/initializers/mime_types.rb +5 -0
  96. data/config/initializers/secret_token.rb +7 -0
  97. data/config/initializers/session_store.rb +8 -0
  98. data/config/locales/en.yml +22 -11
  99. data/config/locales/no.yml +1 -0
  100. data/config/routes.rb +4 -5
  101. data/cruise_build.sh +6 -2
  102. data/db/migrate/004_add_period.rb +22 -22
  103. data/db/migrate/015_add_user_option.rb +5 -19
  104. data/db/migrate/017_increase_backlog_name_limit.rb +10 -0
  105. data/db/migrate/021_create_work_accounts.rb +0 -2
  106. data/db/migrate/20101006092700_rename_backlogs_to_projects.rb +22 -0
  107. data/db/migrate/20101006092700_rename_backlogs_to_projects.rb~ +22 -0
  108. data/db/schema.rb +27 -30
  109. data/db/seeds.rb +7 -0
  110. data/lib/array_helper.rb +0 -8
  111. data/lib/class_table_inheritance.rb +8 -7
  112. data/lib/tasks/backup.rake +3 -3
  113. data/lib/tasks/jdbc.rake +2 -2
  114. data/lib/version_from_history.rb +1 -1
  115. data/public/404.html +23 -7
  116. data/public/422.html +26 -0
  117. data/public/500.html +23 -6
  118. data/public/images/rails.png +0 -0
  119. data/public/javascripts/controls.js +5 -3
  120. data/public/javascripts/dragdrop.js +7 -6
  121. data/public/javascripts/effects.js +8 -13
  122. data/public/javascripts/prototype.js +3381 -1700
  123. data/public/javascripts/rails.js +175 -0
  124. data/public/robots.txt +5 -1
  125. data/script/rails +6 -0
  126. data/test/client/login.rb +0 -2
  127. data/test/client/login_test.rb +1 -1
  128. data/test/client/setup.rb +25 -24
  129. data/test/fixtures/{backlogs.yml → projects.yml} +2 -2
  130. data/test/fixtures/tasks.yml +9 -9
  131. data/test/fixtures/work_lock_subscriptions.yml +2 -2
  132. data/test/fixtures/works.yml +7 -7
  133. data/test/functional/periods_controller_test.rb +1 -1
  134. data/test/functional/{backlogs_controller_test.rb → projects_controller_test.rb} +22 -21
  135. data/test/functional/search_controller_test.rb +1 -1
  136. data/test/functional/tasks_controller_test.rb +17 -17
  137. data/test/functional/user_controller_test.rb +16 -21
  138. data/test/functional/welcome_controller_test.rb +4 -3
  139. data/test/functional/works_controller_test.rb +5 -5
  140. data/test/integration/user_system_test.rb +1 -1
  141. data/test/mocks/test/clock.rb +1 -1
  142. data/test/performance/browsing_test.rb +9 -0
  143. data/test/performance/common.rb +1 -1
  144. data/test/test_helper.rb +23 -6
  145. data/test/test_helper.rb~ +121 -0
  146. data/test/unit/user_test.rb +3 -3
  147. data/test/unit/work_test.rb +7 -7
  148. data/vendor/plugins/assert_cookie/lib/assert_cookie.rb +0 -2
  149. data/vendor/plugins/{foreign_key_migrations → dynamic_form}/MIT-LICENSE +1 -1
  150. data/vendor/plugins/dynamic_form/README +13 -0
  151. data/vendor/plugins/dynamic_form/Rakefile +10 -0
  152. data/vendor/plugins/dynamic_form/dynamic_form.gemspec +12 -0
  153. data/vendor/plugins/dynamic_form/init.rb +1 -0
  154. data/vendor/plugins/dynamic_form/lib/action_view/helpers/dynamic_form.rb +300 -0
  155. data/vendor/plugins/dynamic_form/lib/action_view/locale/en.yml +8 -0
  156. data/vendor/plugins/dynamic_form/lib/dynamic_form.rb +5 -0
  157. data/vendor/plugins/dynamic_form/test/dynamic_form_i18n_test.rb +42 -0
  158. data/vendor/plugins/dynamic_form/test/dynamic_form_test.rb +370 -0
  159. data/vendor/plugins/dynamic_form/test/test_helper.rb +9 -0
  160. data/vendor/plugins/prototype_legacy_helper/lib/prototype_legacy_helper.rb +432 -0
  161. data/vendor/plugins/prototype_legacy_helper/test/test_prototype_helper.rb +297 -0
  162. data/vendor/plugins/rails_time/test/debug.log +1 -0
  163. data/vendor/plugins/{redhillonrails_core → verification}/MIT-LICENSE +1 -1
  164. data/vendor/plugins/verification/README +34 -0
  165. data/vendor/plugins/verification/Rakefile +22 -0
  166. data/vendor/plugins/verification/init.rb +3 -0
  167. data/vendor/plugins/verification/lib/action_controller/verification.rb +132 -0
  168. data/vendor/plugins/verification/test/test_helper.rb +18 -0
  169. data/vendor/plugins/verification/test/verification_test.rb +270 -0
  170. data/vendor/plugins/will_paginate/lib/will_paginate/collection.rb +1 -1
  171. metadata +115 -134
  172. data/Gemfile~ +0 -4
  173. data/History.txt~ +0 -961
  174. data/LICENSE_LOCALIZATION +0 -20
  175. data/README_LOCALIZATION +0 -61
  176. data/README_RAILS +0 -180
  177. data/app/views/backlogs/_form.rhtml +0 -44
  178. data/app/views/backlogs/_name_list.rhtml +0 -5
  179. data/app/views/backlogs/edit.rhtml +0 -14
  180. data/app/views/backlogs/list.rhtml +0 -16
  181. data/app/views/layouts/mwrt002.rhtml +0 -43
  182. data/config/initializers/mongrel.rb +0 -83
  183. data/config/preinitializer.rb +0 -20
  184. data/config/warble.rb~ +0 -84
  185. data/db/migrate/017_insert_datek_projects.rb +0 -98
  186. data/lib/change_column_null_migration_fix.rb +0 -15
  187. data/no_test.rb~ +0 -6
  188. data/public/dispatch.cgi +0 -10
  189. data/public/dispatch.fcgi +0 -24
  190. data/public/dispatch.rb +0 -10
  191. data/script/about +0 -3
  192. data/script/breakpointer +0 -3
  193. data/script/console +0 -3
  194. data/script/dbconsole +0 -3
  195. data/script/destroy +0 -3
  196. data/script/generate +0 -3
  197. data/script/performance/benchmarker +0 -3
  198. data/script/performance/profiler +0 -3
  199. data/script/plugin +0 -3
  200. data/script/process/inspector +0 -3
  201. data/script/process/reaper +0 -3
  202. data/script/process/spawner +0 -3
  203. data/script/runner +0 -3
  204. data/script/server +0 -3
  205. data/test/client/login.rb~ +0 -33
  206. data/test/mocks/test/user_notify.rb +0 -16
  207. data/vendor/plugins/foreign_key_migrations/CHANGELOG +0 -103
  208. data/vendor/plugins/foreign_key_migrations/README +0 -87
  209. data/vendor/plugins/foreign_key_migrations/about.yml +0 -5
  210. data/vendor/plugins/foreign_key_migrations/init.rb +0 -1
  211. data/vendor/plugins/foreign_key_migrations/install.rb +0 -1
  212. data/vendor/plugins/foreign_key_migrations/lib/foreign_key_migrations.rb +0 -3
  213. data/vendor/plugins/foreign_key_migrations/lib/red_hill_consulting/foreign_key_migrations/active_record/base.rb +0 -22
  214. data/vendor/plugins/foreign_key_migrations/lib/red_hill_consulting/foreign_key_migrations/active_record/connection_adapters/abstract_adapter.rb +0 -22
  215. data/vendor/plugins/foreign_key_migrations/lib/red_hill_consulting/foreign_key_migrations/active_record/connection_adapters/table_definition.rb +0 -28
  216. data/vendor/plugins/lightwindow_helper/README +0 -33
  217. data/vendor/plugins/lightwindow_helper/assets/images/ajax-loading.gif +0 -0
  218. data/vendor/plugins/lightwindow_helper/assets/images/arrow-down.gif +0 -0
  219. data/vendor/plugins/lightwindow_helper/assets/images/arrow-up.gif +0 -0
  220. data/vendor/plugins/lightwindow_helper/assets/images/black-70.png +0 -0
  221. data/vendor/plugins/lightwindow_helper/assets/images/black.png +0 -0
  222. data/vendor/plugins/lightwindow_helper/assets/images/nextlabel.gif +0 -0
  223. data/vendor/plugins/lightwindow_helper/assets/images/prevlabel.gif +0 -0
  224. data/vendor/plugins/lightwindow_helper/assets/javascripts/lightwindow.js +0 -1921
  225. data/vendor/plugins/lightwindow_helper/assets/stylesheets/lightwindow.css +0 -376
  226. data/vendor/plugins/lightwindow_helper/init.rb +0 -1
  227. data/vendor/plugins/lightwindow_helper/install.rb +0 -7
  228. data/vendor/plugins/lightwindow_helper/lib/lightwindow_helper.rb +0 -31
  229. data/vendor/plugins/redhillonrails_core/CHANGELOG +0 -150
  230. data/vendor/plugins/redhillonrails_core/README +0 -124
  231. data/vendor/plugins/redhillonrails_core/init.rb +0 -19
  232. data/vendor/plugins/redhillonrails_core/lib/red_hill_consulting/core/active_record/base.rb +0 -54
  233. data/vendor/plugins/redhillonrails_core/lib/red_hill_consulting/core/active_record/connection_adapters/abstract_adapter.rb +0 -31
  234. data/vendor/plugins/redhillonrails_core/lib/red_hill_consulting/core/active_record/connection_adapters/column.rb +0 -21
  235. data/vendor/plugins/redhillonrails_core/lib/red_hill_consulting/core/active_record/connection_adapters/foreign_key_definition.rb +0 -26
  236. data/vendor/plugins/redhillonrails_core/lib/red_hill_consulting/core/active_record/connection_adapters/index_definition.rb +0 -11
  237. data/vendor/plugins/redhillonrails_core/lib/red_hill_consulting/core/active_record/connection_adapters/mysql_adapter.rb +0 -74
  238. data/vendor/plugins/redhillonrails_core/lib/red_hill_consulting/core/active_record/connection_adapters/mysql_column.rb +0 -8
  239. data/vendor/plugins/redhillonrails_core/lib/red_hill_consulting/core/active_record/connection_adapters/postgresql_adapter.rb +0 -99
  240. data/vendor/plugins/redhillonrails_core/lib/red_hill_consulting/core/active_record/connection_adapters/schema_statements.rb +0 -16
  241. data/vendor/plugins/redhillonrails_core/lib/red_hill_consulting/core/active_record/connection_adapters/sqlite3_adapter.rb +0 -9
  242. data/vendor/plugins/redhillonrails_core/lib/red_hill_consulting/core/active_record/connection_adapters/table_definition.rb +0 -27
  243. data/vendor/plugins/redhillonrails_core/lib/red_hill_consulting/core/active_record/schema.rb +0 -27
  244. data/vendor/plugins/redhillonrails_core/lib/red_hill_consulting/core/active_record/schema_dumper.rb +0 -47
  245. data/vendor/plugins/transactional_migrations/CHANGELOG +0 -9
  246. data/vendor/plugins/transactional_migrations/MIT-LICENSE +0 -20
  247. data/vendor/plugins/transactional_migrations/README +0 -15
  248. data/vendor/plugins/transactional_migrations/about.yml +0 -5
  249. data/vendor/plugins/transactional_migrations/init.rb +0 -1
  250. data/vendor/plugins/transactional_migrations/lib/red_hill_consulting/transactional_migrations/active_record/migration.rb +0 -19
@@ -21,7 +21,7 @@ module PeriodsHelper
21
21
  end
22
22
 
23
23
  def add_active_task(page)
24
- page.insert_html(:top, "active_tasks_#{@task.period.id}", render(:partial => "/tasks/task", :locals => { :task => @task, :i => 1, :active => true, :highlight_task => false, :update => :spotlight, :hidden => true, :show_backlog => false }))
24
+ page.insert_html(:top, "active_tasks_#{@task.period.id}", render(:partial => "/tasks/task", :locals => { :task => @task, :i => 1, :active => true, :highlight_task => false, :update => :spotlight, :hidden => true, :show_project => false }))
25
25
 
26
26
  page[:no_tasks_message].hide
27
27
 
@@ -43,9 +43,9 @@ module PeriodsHelper
43
43
  period_tag_id = "completed_period_#{@task.period_id}"
44
44
  page.insert_html :top, "completed_tasks", %Q{<div id="#{period_tag_id}" />}
45
45
  page.insert_html :top, period_tag_id, %Q{<ul id="#{list_tag_id}" class="task_list"/>}
46
- page.insert_html :top, period_tag_id, :partial => '/tasks/fields_header', :locals => {:backlog => @task.backlog, :active => false, :work_done => work_done}
46
+ page.insert_html :top, period_tag_id, :partial => '/tasks/fields_header', :locals => {:project => @task.project, :active => false, :work_done => work_done}
47
47
  end
48
- page.insert_html :top, list_tag_id, :partial => '/tasks/task', :locals => {:active => false, :hidden => true, :highlight_task => false, :show_backlog => true}
48
+ page.insert_html :top, list_tag_id, :partial => '/tasks/task', :locals => {:active => false, :hidden => true, :highlight_task => false, :show_project => true}
49
49
  page.visual_effect :appear, "task_#{@task.id}"
50
50
 
51
51
  end
@@ -1,4 +1,4 @@
1
- module BacklogsHelper
1
+ module ProjectsHelper
2
2
  def remove_active_task(page)
3
3
  page.visual_effect :blind_up, "task_#{@task.id}"
4
4
  last_in_period = @tasks.find {|t| t.period_id == @task.period_id}.nil?
@@ -23,11 +23,11 @@ module BacklogsHelper
23
23
  period_tag_id = "completed_period_#{@task.period_id}"
24
24
  page.insert_html :top, :completed_tasks, "<div id=\"#{period_tag_id}\ />"
25
25
  page.insert_html :top, period_tag_id, "<ul id=\"#{list_tag_id}\" class=\"task_list\" />"
26
- page.insert_html :top, period_tag_id, :partial => '/tasks/fields_header', :locals => {:backlog => @task.backlog, :active => false, :work_done => work_done}
26
+ page.insert_html :top, period_tag_id, :partial => '/tasks/fields_header', :locals => {:project => @task.project, :active => false, :work_done => work_done}
27
27
  page.insert_html :top, period_tag_id, :partial => '/tasks/period_header', :locals => {:period => @task.period}
28
28
  end
29
29
 
30
- page.insert_html :top, list_tag_id, :partial => '/tasks/task', :locals => {:active => false, :hidden => true, :highlight_task => false, :show_backlog => false}
30
+ page.insert_html :top, list_tag_id, :partial => '/tasks/task', :locals => {:task => @task, :active => false, :hidden => true, :highlight_task => false, :show_project => false}
31
31
  page.visual_effect :appear, "task_#{@task.id}"
32
32
  end
33
33
 
@@ -55,12 +55,12 @@ module BacklogsHelper
55
55
  page.insert_html :after, "active_period_#{@task.period.higher_item.id}", period_tag
56
56
  end
57
57
  page.insert_html :top, period_tag_id, %Q{<ul id="#{list_tag_id}" class="task_list" style="width: 100%;"/>}
58
- fields_header = render(:partial => '/tasks/fields_header', :locals => { :backlog => @task.backlog, :active => true, :track_todo => @task.backlog.track_todo?, :track_done => @task.backlog.track_done?, :track_times => tasks_in_period.find {|t|t.period && t.period.active?} } )
58
+ fields_header = render(:partial => '/tasks/fields_header', :locals => { :project => @task.project, :active => true, :track_todo => @task.project.track_todo?, :track_done => @task.project.track_done?, :track_times => tasks_in_period.find {|t|t.period && t.period.active?} } )
59
59
  page.insert_html :top, period_tag_id, fields_header
60
60
  page.insert_html :top, period_tag_id, render(:partial => "/tasks/period_header", :locals => {:period => @task.period})
61
61
  end
62
62
 
63
- page.insert_html(:top, list_tag_id, render(:partial => "/tasks/task", :locals => { :task => @task, :i => 1, :active => true, :highlight_task => false, :update => :spotlight, :hidden => true, :show_backlog => false }))
63
+ page.insert_html(:top, list_tag_id, render(:partial => "/tasks/task", :locals => { :task => @task, :i => 1, :active => true, :highlight_task => false, :update => :spotlight, :hidden => true, :show_project => false }))
64
64
  record page, sortable_element_js(list_tag_id, :url => { :action => :order }, :containment => @tasks.map{|t| t.period_id}.uniq.map{|p| "active_tasks_#{p}"}, :constraint => false)
65
65
 
66
66
  page[:no_tasks_message].hide
@@ -7,7 +7,7 @@ module UserHelper
7
7
  }.freeze unless defined? DEFAULT_HEAD_OPTIONS
8
8
 
9
9
  def title_helper
10
- "#{controller.controller_class_name} #{controller.action_name}"
10
+ "#{controller.class.name} #{controller.action_name}"
11
11
  end
12
12
 
13
13
  def head_helper(label, options = {})
@@ -35,7 +35,7 @@ module UserHelper
35
35
 
36
36
  def start_form_tag_helper(options = {})
37
37
  url = url_for(:action => "#{controller.action_name}")
38
- "#{self.send(:form_tag, url, options)}"
38
+ "#{self.send(:form_tag, url, options)}".html_safe
39
39
  end
40
40
 
41
41
  def user_id
@@ -72,4 +72,5 @@ class UserNotify < ActionMailer::Base
72
72
  @sent_on = Time.now
73
73
  @headers['Content-Type'] = "text/plain; charset=#{UserSystem::CONFIG[:mail_charset]}; format=flowed"
74
74
  end
75
+
75
76
  end
@@ -7,8 +7,8 @@ class Absence < ActiveRecord::Base
7
7
 
8
8
  validates_uniqueness_of :on, :scope => :user_id
9
9
 
10
- def validate
11
- if PublicHoliday.exists? :on => on
10
+ validate do |a|
11
+ if PublicHoliday.exists? :on => a.on
12
12
  errors.add :on, "You cannot mark absence on a public holiday."
13
13
  end
14
14
  end
File without changes
@@ -10,8 +10,8 @@ class Estimate < ActiveRecord::Base
10
10
  validates_associated :task
11
11
  validates_presence_of :todo
12
12
 
13
- def after_create
14
- task.finish(Task::COMPLETED, false) if todo == 0
13
+ after_create do |e|
14
+ e.task.finish(Task::COMPLETED, false) if todo == 0
15
15
  end
16
16
 
17
17
  end
@@ -23,6 +23,5 @@ class Party < ActiveRecord::Base
23
23
  0
24
24
  end
25
25
  end
26
-
27
-
26
+
28
27
  end
@@ -8,9 +8,7 @@ class Period < ActiveRecord::Base
8
8
  validates_associated :party
9
9
  validates_uniqueness_of :position, :scope => :party_id
10
10
 
11
- def validate
12
- errors.add "A period cannot end before it starts" unless end_on >= start_on
13
- end
11
+ validate { |p| p.errors.add "A period cannot end before it starts" unless p.end_on >= p.start_on }
14
12
 
15
13
  def self.find_active_or_future(check_tasks = false)
16
14
  periods = find(:all, :conditions => "end_on >= '#{Date.today.strftime '%Y-%m-%d'}'")
@@ -36,15 +34,15 @@ class Period < ActiveRecord::Base
36
34
  tasks.select {|task| task.active?}
37
35
  end
38
36
 
39
- def most_frequent_backlog
40
- all_backlogs = tasks.map {|t| t.backlog}.compact
41
- return nil if all_backlogs.empty?
37
+ def most_frequent_project
38
+ all_projects = tasks.map {|t| t.project}.compact
39
+ return nil if all_projects.empty?
42
40
  freq = {}
43
- all_backlogs.each do |b|
41
+ all_projects.each do |b|
44
42
  freq[b.id] ||= 0
45
43
  freq[b.id] += 1
46
44
  end
47
- freq.to_a.sort_by {|backlog, count| -count}.first[0]
45
+ freq.to_a.sort_by {|project, count| -count}.first[0]
48
46
  end
49
47
 
50
48
  def active?(check_tasks = false)
@@ -133,7 +131,7 @@ class Period < ActiveRecord::Base
133
131
  last = first + 6
134
132
  works = tasks.map {|t| t.works_with_children}.flatten
135
133
  works.reject! {|work| work.hours == 0} unless with_empty_works
136
- works.reject! {|work| work.user_id != user_id} if user_id && backlog.enable_users
134
+ works.reject! {|work| work.user_id != user_id} if user_id && project.enable_users
137
135
  by_day = (0..6).map do |i|
138
136
  works.select {|w| w.completed_at && w.completed_at.to_date == first + i}.sort do |w1, w2|
139
137
  if w1.completed_at != w2.completed_at
@@ -154,31 +152,32 @@ class Period < ActiveRecord::Base
154
152
  end
155
153
 
156
154
  def estimates?
157
- not backlogs.find {|backlog| backlog.track_todo?}.nil?
155
+ not projects.find {|project| project.track_todo?}.nil?
158
156
  end
159
157
 
160
158
  def track_times?
161
- not backlogs.find {|backlog| backlog.track_times?}.nil?
159
+ not projects.find {|project| project.track_times?}.nil?
162
160
  end
163
161
 
164
162
  def enable_subtasks?
165
- not backlogs.find {|backlog| backlog.enable_subtasks?}.nil?
163
+ not projects.find {|project| project.enable_subtasks?}.nil?
166
164
  end
167
165
 
168
166
  def invoice?
169
- not backlogs.find {|backlog| backlog.enable_invoicing?}.nil?
167
+ not projects.find {|project| project.enable_invoicing?}.nil?
170
168
  end
171
169
 
172
- def backlogs
173
- tasks.map {|task| task.backlog}.uniq
170
+ def projects
171
+ tasks.map {|task| task.project}.uniq
174
172
  end
175
173
 
176
174
  def burn_down_graph(size)
177
175
  begin
178
176
  require 'gruff'
179
- rescue MissingSourceFile => e
180
- return File.read("public/images/rmagick_#{size}.gif") if File.exists? "public/images/rmagick_#{size}.gif"
181
- return File.read("public/images/rmagick.gif")
177
+ rescue MissingSourceFile => e
178
+ matching_file_name = Rails.root.to_s + "/public/images/rmagick_#{size}.gif"
179
+ return File.read(matching_file_name) if File.exists? matching_file_name
180
+ return File.read(Rails.root.to_s + "/public/images/rmagick.gif")
182
181
  end
183
182
  g = Gruff::Line.new(size)
184
183
  g.theme_37signals
@@ -1,4 +1,4 @@
1
- class Backlog < ActiveRecord::Base
1
+ class Project < ActiveRecord::Base
2
2
  validates_presence_of :name
3
3
  validates_length_of :name, :allow_nil => false, :maximum => 64
4
4
  validates_uniqueness_of :name
@@ -11,7 +11,7 @@ class Backlog < ActiveRecord::Base
11
11
  has_many :tasks, :order => 'period_id, position', :dependent => :destroy
12
12
  has_many :unplanned_tasks, :class_name => 'Task', :conditions => 'period_id IS NULL', :order => 'position'
13
13
  has_many :works, :dependent => :destroy
14
- has_and_belongs_to_many :work_lock_subscribers, :class_name => 'User', :join_table => "work_lock_subscriptions", :foreign_key => "backlog_id", :association_foreign_key => 'subscriber_user_id'
14
+ has_and_belongs_to_many :work_lock_subscribers, :class_name => 'User', :join_table => "work_lock_subscriptions", :foreign_key => "project_id", :association_foreign_key => 'subscriber_user_id'
15
15
 
16
16
  validates_inclusion_of :track_times, :in => [true, false], :message => I18n.translate('activerecord.errors.messages')[:blank]
17
17
 
@@ -1,7 +1,7 @@
1
1
  require 'action_view/helpers/url_helper'
2
2
 
3
3
  class Sidebar
4
- include ActionView::Helpers::UrlHelper
4
+ include Rails.application.routes.url_helpers
5
5
  include ActionView::Helpers::TagHelper
6
6
  include ERB::Util
7
7
 
@@ -28,7 +28,7 @@ class Sidebar
28
28
  started_tasks = Task.find_started
29
29
  if not started_tasks.empty?
30
30
  links = started_tasks.map do |task|
31
- "<li><a href=\"#{url_for :controller => 'tasks', :action => :list_started, :id => task.id}\">#{task.description}</a></li>"
31
+ "<li><a href=\"#{url_for(:host => @controller.request.host_with_port, :controller => 'tasks', :action => 'list_started', :id => task.id)}\">#{task.description}</a></li>"
32
32
  end
33
33
  blocks.unshift({ :title => @controller.l(:started_tasks),
34
34
  :options => {:controller => 'tasks', :action => :list_started},
@@ -9,7 +9,7 @@ class Task < ActiveRecord::Base
9
9
  MOVED = 'MOVED'
10
10
  ABORTED = 'ABORTED'
11
11
 
12
- belongs_to :backlog
12
+ belongs_to :project
13
13
  belongs_to :period
14
14
  belongs_to :ancestor_task, :class_name => 'Task', :foreign_key => 'previous_task_id'
15
15
  belongs_to :customer
@@ -21,33 +21,33 @@ class Task < ActiveRecord::Base
21
21
  belongs_to :creator, :class_name => 'User', :foreign_key => 'created_by'
22
22
  belongs_to :updater, :class_name => 'User', :foreign_key => 'updated_by'
23
23
 
24
- acts_as_list :scope => '#{parent_id ? "parent_id = #{parent_id}" : period_id ? "period_id = #{period_id}" : "period_id IS NULL AND parent_id IS NULL AND backlog_id = #{backlog_id}"} AND finished_at IS NULL'
24
+ acts_as_list :scope => '#{parent_id ? "parent_id = #{parent_id}" : period_id ? "period_id = #{period_id}" : "period_id IS NULL AND parent_id IS NULL AND project_id = #{project_id}"} AND finished_at IS NULL'
25
25
  acts_as_tree :order => 'position'
26
26
 
27
- validates_presence_of :backlog_id, :if => Proc.new { |task| task.parent_id.nil? }
28
- validates_presence_of :parent_id, :if => Proc.new { |task| task.backlog_id.nil? }
27
+ validates_presence_of :project_id, :if => Proc.new { |task| task.parent_id.nil? }
28
+ validates_presence_of :parent_id, :if => Proc.new { |task| task.project_id.nil? }
29
29
  validates_presence_of :position, :on => :update, :if => Proc.new { |task| task.finished_at.nil? }
30
30
  validates_presence_of :finished_at, :on => :update, :if => Proc.new { |task| task.position.nil? }
31
31
  validates_presence_of :resolution, :if => :finished_at
32
- validates_presence_of :description, :if => :backlog_id
32
+ validates_presence_of :description, :if => :project_id
33
33
 
34
34
  validates_size_of :description, :maximum => 80, :if => :description
35
35
 
36
- #validates_uniqueness_of :description, :scope => :backlog_id, :if => Proc.new {|task| task.backlog_id && task.previous_task_id.nil?}
36
+ #validates_uniqueness_of :description, :scope => :project_id, :if => Proc.new {|task| task.project_id && task.previous_task_id.nil?}
37
37
  validates_uniqueness_of :description, :scope => :period_id, :if => :period_id
38
38
  validates_uniqueness_of :position, :scope => :parent_id, :if => :parent_id, :allow_nil => true
39
39
  validates_uniqueness_of :position, :scope => :period_id, :if => :period_id, :allow_nil => true
40
- validates_uniqueness_of :position, :scope => [:period_id, :parent_id, :backlog_id], :if => Proc.new {|task| task.period_id.nil? && task.parent_id.nil?}, :allow_nil => true
40
+ validates_uniqueness_of :position, :scope => [:period_id, :parent_id, :project_id], :if => Proc.new {|task| task.period_id.nil? && task.parent_id.nil?}, :allow_nil => true
41
41
 
42
42
  before_create {|record| record.created_by = current_user.id}
43
43
  before_save {|record| record.updated_by = current_user.id}
44
44
 
45
- def validate
46
- if self.parent_id && (self.period_id || self.backlog_id)
47
- errors.add :parent_id, "A subtask may have neither period nor backlog set."
45
+ validate do |r|
46
+ if r.parent_id && (r.period_id || r.project_id)
47
+ r.errors.add :parent_id, "A subtask may have neither period nor project set."
48
48
  end
49
- if new_record? && self.period && self.period.passed?
50
- errors.add :period_id, "You may not add a task to a past period."
49
+ if r.new_record? && r.period && r.period.passed?
50
+ r.errors.add :period_id, "You may not add a task to a past period."
51
51
  end
52
52
  end
53
53
 
@@ -61,7 +61,7 @@ class Task < ActiveRecord::Base
61
61
  end
62
62
  conditions = "start_time IS NOT NULL AND completed_at IS NULL AND (user_id IS NULL#{user_clause})"
63
63
  Work.find(:all, :conditions => conditions).map {|work| work.task}.compact.sort_by do |t|
64
- [t.root_task.backlog.name, t.root_task.period ? t.root_task.period.end_on : 0, t.position || 0]
64
+ [t.root_task.project.name, t.root_task.period ? t.root_task.period.end_on : 0, t.position || 0]
65
65
  end
66
66
  end
67
67
 
@@ -173,7 +173,7 @@ class Task < ActiveRecord::Base
173
173
  end
174
174
  existing_task = Task.find_descendant(new_period && new_period.id, ancestor_id)
175
175
  if existing_task ||= Task.find_by_period_id_and_previous_task_id(new_period && new_period.id, ancestor_id)
176
- raise "mismatch" unless existing_task.backlog == root_task.backlog
176
+ raise "mismatch" unless existing_task.project == root_task.project
177
177
  raise "Mismatch" unless existing_task.period == new_period
178
178
  existing_task.open
179
179
  existing_task.previous_task_id = self.previous_task_id || self.id
@@ -189,7 +189,7 @@ class Task < ActiveRecord::Base
189
189
  new_parent = Task.find_descendant(new_period.id, parent.ancestor_id)
190
190
  new_task.parent = new_parent
191
191
  else
192
- new_task.backlog = root_task.backlog
192
+ new_task.project = root_task.project
193
193
  new_task.period = new_period
194
194
  end
195
195
  new_task.description = self.description
@@ -279,35 +279,35 @@ class Task < ActiveRecord::Base
279
279
  end
280
280
 
281
281
  def invoicing?
282
- root_task.backlog.enable_invoicing?
282
+ root_task.project.enable_invoicing?
283
283
  end
284
284
 
285
285
  def track_done?
286
- backlog.track_done?
286
+ project.track_done?
287
287
  end
288
288
 
289
289
  def track_times?
290
- backlog.try :track_times?
290
+ project.try :track_times?
291
291
  end
292
292
 
293
293
  def track_todo?
294
- root_task.backlog.track_todo?
294
+ root_task.project.track_todo?
295
295
  end
296
296
 
297
297
  def enable_subtasks?
298
- root_task.backlog.enable_subtasks?
298
+ root_task.project.enable_subtasks?
299
299
  end
300
300
 
301
301
  def enable_users?
302
- root_task.backlog.enable_users?
302
+ root_task.project.enable_users?
303
303
  end
304
304
 
305
305
  def enable_customer?
306
- root_task.backlog.enable_customer?
306
+ root_task.project.enable_customer?
307
307
  end
308
308
 
309
309
  def enable_invoicing?
310
- root_task.backlog.enable_invoicing?
310
+ root_task.project.enable_invoicing?
311
311
  end
312
312
 
313
313
  alias_method :old_period, :period
@@ -315,9 +315,9 @@ class Task < ActiveRecord::Base
315
315
  old_period || root_task.old_period
316
316
  end
317
317
 
318
- alias_method :old_backlog, :backlog
319
- def backlog
320
- old_backlog || root_task.old_backlog
318
+ alias_method :old_project, :project
319
+ def project
320
+ old_project || root_task.old_project
321
321
  end
322
322
 
323
323
  def depth
@@ -380,7 +380,7 @@ class Task < ActiveRecord::Base
380
380
  end
381
381
 
382
382
  new_work.user = current_user
383
- new_work.backlog_id = backlog.id
383
+ new_work.project_id = project.id
384
384
  new_work.save!
385
385
  works << new_work
386
386
  end
@@ -412,7 +412,7 @@ class Task < ActiveRecord::Base
412
412
 
413
413
  def description_with_parents
414
414
  if parent.nil?
415
- "#{backlog.name}: #{description}"
415
+ "#{project.name}: #{description}"
416
416
  else
417
417
  "#{parent.description_with_parents} - #{description}"
418
418
  end
@@ -1,4 +1,5 @@
1
1
  require 'digest/sha1'
2
+ require 'clock'
2
3
 
3
4
  # this model expects a certain database layout and its based on the name/login pattern.
4
5
  #class User < ActiveRecord::Base
@@ -124,15 +125,15 @@ class User < Party
124
125
 
125
126
  def crypt_password
126
127
  if @password_needs_confirmation
127
- write_attribute("salt", self.class.hashed("salt-#{Clock.now}"))
128
- write_attribute("salted_password", self.class.salted_password(salt, self.class.hashed(@password)))
128
+ self[:salt] = self.class.hashed("salt-#{Clock.now}")
129
+ self[:salted_password] = self.class.salted_password(salt, self.class.hashed(@password))
129
130
  end
130
131
  end
131
132
 
132
133
  def new_security_token
133
134
  expiry = Time.at(Clock.now.to_i + self.class.token_lifetime)
134
- write_attribute('security_token', self.class.hashed(self.salted_password + Clock.now.to_i.to_s + rand.to_s))
135
- write_attribute('token_expiry', expiry)
135
+ self[:security_token] = self.class.hashed(self.salted_password + Clock.now.to_i.to_s + rand.to_s)
136
+ self[:token_expiry] = expiry
136
137
  # update_without_callbacks
137
138
  update
138
139
  return self.security_token
@@ -4,11 +4,11 @@ class Work < ActiveRecord::Base
4
4
 
5
5
  belongs_to :task
6
6
  belongs_to :user
7
- belongs_to :backlog
7
+ belongs_to :project
8
8
  belongs_to :customer
9
9
 
10
10
  validates_associated :task
11
- validates_presence_of :backlog
11
+ validates_presence_of :project
12
12
  validates_presence_of :started_on
13
13
  validates_presence_of :start_time, :if => :track_times?
14
14
 
@@ -18,7 +18,7 @@ class Work < ActiveRecord::Base
18
18
  end
19
19
 
20
20
  def track_times?
21
- backlog && backlog.track_times?
21
+ project && project.track_times?
22
22
  end
23
23
 
24
24
  # Return an array with an array of works per day:
@@ -44,53 +44,53 @@ class Work < ActiveRecord::Base
44
44
 
45
45
  # Return a hash with work accounts as keys an array of work hours totals per day as values:
46
46
  # {
47
- # <#Backlog#1> => [ 8, 7, 9, 12, 4, nil, nil],
48
- # <#Backlog#2> => [nil, 1, nil, nil, 4, nil, nil],
49
- # <#Backlog#3> => [nil, nil, nil, nil, nil, 4, 3],
47
+ # <#Project#1> => [ 8, 7, 9, 12, 4, nil, nil],
48
+ # <#Project#2> => [nil, 1, nil, nil, 4, nil, nil],
49
+ # <#Project#3> => [nil, nil, nil, nil, nil, 4, 3],
50
50
  # ]
51
- def self.works_for_week_by_backlog(year, week_no, user = current_user)
51
+ def self.works_for_week_by_project(year, week_no, user = current_user)
52
52
  first_date = Date.commercial(year, week_no, 1)
53
53
  last_date = first_date + 6
54
54
  works = find(:all, :conditions => "user_id #{user ? " = #{user.id}" : "IS NULL"} AND started_on BETWEEN '#{first_date}' AND '#{last_date}'", :order => 'completed_at, started_on, start_time')
55
55
  result = {}
56
56
  works.each do |work|
57
57
  day_of_week = work.started_on.cwday - 1
58
- result[work.backlog] ||= []
59
- result[work.backlog][day_of_week] ||= BigDecimal('0')
60
- result[work.backlog][day_of_week] += work.hours
58
+ result[work.project] ||= []
59
+ result[work.project][day_of_week] ||= BigDecimal('0')
60
+ result[work.project][day_of_week] += work.hours
61
61
  end
62
- result.values.each {|backlog_totals| backlog_totals[6] ||= nil}
63
- result.values.each {|backlog_totals| (0..6).each {|i| backlog_totals[i] = nil if backlog_totals[i] == 0}}
62
+ result.values.each {|project_totals| project_totals[6] ||= nil}
63
+ result.values.each {|project_totals| (0..6).each {|i| project_totals[i] = nil if project_totals[i] == 0}}
64
64
  result
65
65
  end
66
66
 
67
67
  # Return a hash with an array of work totals per day:
68
68
  # {
69
- # backlog1.id => [[m, t, w, t, f, s, s], [m, t, w, t, f, s, s]],
70
- # backlog2.id => [<work for monday>, 0, <work for wednesday>, <work for thursday>, <work for friday>, 0, <work for sunday>]
69
+ # project1.id => [[m, t, w, t, f, s, s], [m, t, w, t, f, s, s]],
70
+ # project2.id => [<work for monday>, 0, <work for wednesday>, <work for thursday>, <work for friday>, 0, <work for sunday>]
71
71
  # }
72
72
  def self.work_totals_for_week(year, week_no, user = current_user)
73
73
  first = Date.commercial(year, week_no, 1)
74
74
  last = first + 6
75
75
  works = find(:all, :conditions => "completed_at IS NOT NULL AND started_on BETWEEN '#{first}' AND '#{last}'", :order => 'started_on, start_time, completed_at')
76
- totals_per_backlog = {}
77
- works.map{|w| w.backlog}.uniq.each do |backlog|
78
- totals_per_backlog[backlog.id] = [[], []]
76
+ totals_per_project = {}
77
+ works.map{|w| w.project}.uniq.each do |project|
78
+ totals_per_project[project.id] = [[], []]
79
79
  (0..6).each do |day|
80
- works_for_day = works.select {|work| (work.backlog == backlog) && (work.started_on == (first + day)) && ((user.nil? && work.user_id.nil?) || (user && work.user_id == user.id)) }
80
+ works_for_day = works.select {|work| (work.project == project) && (work.started_on == (first + day)) && ((user.nil? && work.user_id.nil?) || (user && work.user_id == user.id)) }
81
81
  invoice_works_for_day = works_for_day.select {|work| work.invoice? }
82
82
  internal_works_for_day = works_for_day.select {|work| !work.invoice? }
83
83
 
84
84
  invoice_day_total = invoice_works_for_day.reduce(BigDecimal('0')){|total, work| total += work.hours}
85
85
  internal_day_total = internal_works_for_day.reduce(BigDecimal('0')){|total, work| total += work.hours}
86
- totals_per_backlog[backlog.id][0] << invoice_day_total
87
- totals_per_backlog[backlog.id][1] << internal_day_total
86
+ totals_per_project[project.id][0] << invoice_day_total
87
+ totals_per_project[project.id][1] << internal_day_total
88
88
  end
89
89
  end
90
- totals_per_backlog.reject! do |backlog_id, day_totals|
90
+ totals_per_project.reject! do |project_id, day_totals|
91
91
  !day_totals[0].find{|day_total| day_total > 0} && !day_totals[1].find{|day_total| day_total > 0}
92
92
  end
93
- totals_per_backlog
93
+ totals_per_project
94
94
  end
95
95
 
96
96
  def self.find_work_for_day(date, user = current_user)
@@ -157,6 +157,12 @@ class Work < ActiveRecord::Base
157
157
  self.started_on = Date.new(t.year, t.month, t.day)
158
158
  self.start_time = TimeOfDay.new(t.hour, t.min)
159
159
  end
160
+
161
+ def started_on=(new_value)
162
+ super
163
+ self.completed_at_time = completed_at_time.to_s if self.started_on_was.nil?
164
+ self.started_on
165
+ end
160
166
 
161
167
  def completed_at_time
162
168
  completed_at && completed_at.time_of_day
@@ -169,7 +175,7 @@ class Work < ActiveRecord::Base
169
175
  return
170
176
  end
171
177
  time_of_day = TimeOfDay.parse(new_value)
172
- date = started_on || completed_at.to_date || Date.today
178
+ date = started_on || completed_at.try(:to_date) || Date.today
173
179
  self.completed_at = date.at time_of_day
174
180
  end
175
181