backlog 0.36.2 → 0.37.1

Sign up to get free protection for your applications and to get access to all the features.
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