backlog 0.0.4 → 0.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 (170) hide show
  1. data/History.txt +10 -0
  2. data/Rakefile +2 -1
  3. data/app/controllers/application.rb +55 -8
  4. data/app/controllers/groups_controller.rb +62 -0
  5. data/app/controllers/periods_controller.rb +13 -55
  6. data/app/controllers/tasks_controller.rb +9 -5
  7. data/app/controllers/works_controller.rb +43 -6
  8. data/app/helpers/application_helper.rb +20 -2
  9. data/app/helpers/groups_helper.rb +2 -0
  10. data/app/models/backlog.rb +19 -10
  11. data/app/models/estimate.rb +2 -1
  12. data/app/models/group.rb +11 -0
  13. data/app/models/party.rb +3 -0
  14. data/app/models/period.rb +43 -6
  15. data/app/models/task.rb +27 -14
  16. data/app/models/user.rb +37 -8
  17. data/app/models/work.rb +4 -6
  18. data/app/views/backlogs/_name_list.rhtml +5 -0
  19. data/app/views/backlogs/show.rhtml +4 -4
  20. data/app/views/groups/_form.rhtml +7 -0
  21. data/app/views/groups/edit.rhtml +31 -0
  22. data/app/views/groups/list.rhtml +27 -0
  23. data/app/views/groups/new.rhtml +8 -0
  24. data/app/views/layouts/wide.rhtml +2 -2
  25. data/app/views/periods/_burn_down_chart.rhtml +1 -1
  26. data/app/views/periods/_form.rhtml +13 -9
  27. data/app/views/periods/_show_active.rhtml +6 -12
  28. data/app/views/periods/_title.rhtml +4 -5
  29. data/app/views/periods/edit.rhtml +1 -1
  30. data/app/views/periods/new.rhtml +1 -1
  31. data/app/views/periods/show.rhtml +10 -6
  32. data/app/views/tasks/_backlog_header.rhtml +22 -0
  33. data/app/views/tasks/_description_list.rhtml +5 -0
  34. data/app/views/tasks/_form.rhtml +26 -7
  35. data/app/views/tasks/_task.rhtml +4 -4
  36. data/app/views/tasks/edit.rhtml +2 -3
  37. data/app/views/tasks/list_started.rhtml +1 -0
  38. data/app/views/tasks/new.rhtml +2 -2
  39. data/app/views/works/_buttons.rhtml +3 -0
  40. data/app/views/works/_form.rhtml +15 -10
  41. data/app/views/works/daily_work_sheet.rhtml +30 -18
  42. data/app/views/works/edit.rhtml +4 -4
  43. data/app/views/works/list.rhtml +2 -2
  44. data/app/views/works/new.rhtml +3 -2
  45. data/app/views/works/weekly_work_sheet.rhtml +2 -2
  46. data/bin/backlog +2 -0
  47. data/bin/backlog_init.d_kubosch_production +27 -0
  48. data/bin/copy_production2development.rb +33 -0
  49. data/config/database.yml +13 -7
  50. data/config/deploy_kubosch.rb +1 -0
  51. data/config/environment.rb +2 -0
  52. data/config/environments/development_mysql.rb +27 -0
  53. data/config/environments/kubosch_production_mysql.rb +21 -0
  54. data/config/routes.rb +1 -1
  55. data/db/migrate/{001_tasks.rb → 001_create_tasks.rb} +1 -1
  56. data/db/migrate/{002_backlogs.rb → 002_create_backlogs.rb} +2 -2
  57. data/db/migrate/003_add_estimation_points.rb +1 -1
  58. data/db/migrate/004_add_period.rb +2 -2
  59. data/db/migrate/013_create_estimates.rb +1 -1
  60. data/db/migrate/015_add_user_option.rb +9 -5
  61. data/db/migrate/017_insert_datek_projects.rb +13 -10
  62. data/db/migrate/018_create_groups.rb +115 -0
  63. data/db/schema.rb +72 -12
  64. data/lang/en.yaml +7 -0
  65. data/lang/no.yaml +7 -0
  66. data/lib/big_decimal_yaml_fix.rb +27 -0
  67. data/lib/class_table_inheritance.rb +163 -0
  68. data/lib/tasks/backup.rake +92 -0
  69. data/public/images/person.org.png +0 -0
  70. data/public/images/person.png +0 -0
  71. data/public/stylesheets/backlog.css +3 -1
  72. data/public/stylesheets/mwrt002.css +1 -1
  73. data/test/fixtures/groups.yml +6 -0
  74. data/test/fixtures/parties.yml +31 -0
  75. data/test/fixtures/periods.yml +2 -2
  76. data/test/fixtures/tasks.yml +2 -0
  77. data/test/fixtures/users.yml +6 -6
  78. data/test/functional/backlogs_controller_test.rb +1 -1
  79. data/test/functional/groups_controller_test.rb +120 -0
  80. data/test/functional/periods_controller_test.rb +1 -1
  81. data/test/functional/tasks_controller_test.rb +16 -1
  82. data/test/functional/user_controller_test.rb +8 -2
  83. data/test/test_helper.rb +5 -0
  84. data/test/unit/big_decimal_yaml_fix_test.rb +14 -0
  85. data/test/unit/estimate_test.rb +1 -1
  86. data/test/unit/group_test.rb +10 -0
  87. data/test/unit/user_test.rb +56 -44
  88. data/tmp/sessions/ruby_sess.22dec3e9df47fb4e +0 -0
  89. data/tmp/sessions/ruby_sess.8037e0ab58cbcf1a +0 -0
  90. data/vendor/plugins/activerecord_foreign_key_extensions/lib/active_record_extensions.rb +35 -0
  91. data/vendor/rails/actionmailer/test/fixtures/test_mailer/implicitly_multipart_example.rhtml.bak +1 -0
  92. data/vendor/rails/{actionwebservice/lib/action_web_service/templates/scaffolds/layout.rhtml → railties/configs/empty.log} +0 -0
  93. metadata +36 -105
  94. data/backlog.gemspec +0 -21
  95. data/vendor/rails/actionwebservice/CHANGELOG +0 -265
  96. data/vendor/rails/actionwebservice/MIT-LICENSE +0 -21
  97. data/vendor/rails/actionwebservice/README +0 -364
  98. data/vendor/rails/actionwebservice/Rakefile +0 -171
  99. data/vendor/rails/actionwebservice/TODO +0 -32
  100. data/vendor/rails/actionwebservice/examples/googlesearch/README +0 -143
  101. data/vendor/rails/actionwebservice/examples/googlesearch/autoloading/google_search_api.rb +0 -50
  102. data/vendor/rails/actionwebservice/examples/googlesearch/autoloading/google_search_controller.rb +0 -57
  103. data/vendor/rails/actionwebservice/examples/googlesearch/delegated/google_search_service.rb +0 -108
  104. data/vendor/rails/actionwebservice/examples/googlesearch/delegated/search_controller.rb +0 -7
  105. data/vendor/rails/actionwebservice/examples/googlesearch/direct/google_search_api.rb +0 -50
  106. data/vendor/rails/actionwebservice/examples/googlesearch/direct/search_controller.rb +0 -58
  107. data/vendor/rails/actionwebservice/examples/metaWeblog/README +0 -17
  108. data/vendor/rails/actionwebservice/examples/metaWeblog/apis/blogger_api.rb +0 -60
  109. data/vendor/rails/actionwebservice/examples/metaWeblog/apis/blogger_service.rb +0 -34
  110. data/vendor/rails/actionwebservice/examples/metaWeblog/apis/meta_weblog_api.rb +0 -67
  111. data/vendor/rails/actionwebservice/examples/metaWeblog/apis/meta_weblog_service.rb +0 -48
  112. data/vendor/rails/actionwebservice/examples/metaWeblog/controllers/xmlrpc_controller.rb +0 -16
  113. data/vendor/rails/actionwebservice/install.rb +0 -30
  114. data/vendor/rails/actionwebservice/lib/action_web_service.rb +0 -66
  115. data/vendor/rails/actionwebservice/lib/action_web_service/api.rb +0 -301
  116. data/vendor/rails/actionwebservice/lib/action_web_service/base.rb +0 -42
  117. data/vendor/rails/actionwebservice/lib/action_web_service/casting.rb +0 -138
  118. data/vendor/rails/actionwebservice/lib/action_web_service/client.rb +0 -3
  119. data/vendor/rails/actionwebservice/lib/action_web_service/client/base.rb +0 -28
  120. data/vendor/rails/actionwebservice/lib/action_web_service/client/soap_client.rb +0 -113
  121. data/vendor/rails/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb +0 -58
  122. data/vendor/rails/actionwebservice/lib/action_web_service/container.rb +0 -3
  123. data/vendor/rails/actionwebservice/lib/action_web_service/container/action_controller_container.rb +0 -93
  124. data/vendor/rails/actionwebservice/lib/action_web_service/container/delegated_container.rb +0 -86
  125. data/vendor/rails/actionwebservice/lib/action_web_service/container/direct_container.rb +0 -69
  126. data/vendor/rails/actionwebservice/lib/action_web_service/dispatcher.rb +0 -2
  127. data/vendor/rails/actionwebservice/lib/action_web_service/dispatcher/abstract.rb +0 -207
  128. data/vendor/rails/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +0 -379
  129. data/vendor/rails/actionwebservice/lib/action_web_service/invocation.rb +0 -202
  130. data/vendor/rails/actionwebservice/lib/action_web_service/protocol.rb +0 -4
  131. data/vendor/rails/actionwebservice/lib/action_web_service/protocol/abstract.rb +0 -112
  132. data/vendor/rails/actionwebservice/lib/action_web_service/protocol/discovery.rb +0 -37
  133. data/vendor/rails/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb +0 -176
  134. data/vendor/rails/actionwebservice/lib/action_web_service/protocol/soap_protocol/marshaler.rb +0 -235
  135. data/vendor/rails/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb +0 -122
  136. data/vendor/rails/actionwebservice/lib/action_web_service/scaffolding.rb +0 -283
  137. data/vendor/rails/actionwebservice/lib/action_web_service/struct.rb +0 -68
  138. data/vendor/rails/actionwebservice/lib/action_web_service/support/class_inheritable_options.rb +0 -26
  139. data/vendor/rails/actionwebservice/lib/action_web_service/support/signature_types.rb +0 -226
  140. data/vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/layout.erb +0 -65
  141. data/vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/methods.erb +0 -6
  142. data/vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/methods.rhtml +0 -0
  143. data/vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.erb +0 -29
  144. data/vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml +0 -0
  145. data/vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/result.erb +0 -30
  146. data/vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/result.rhtml +0 -0
  147. data/vendor/rails/actionwebservice/lib/action_web_service/test_invoke.rb +0 -110
  148. data/vendor/rails/actionwebservice/lib/action_web_service/version.rb +0 -9
  149. data/vendor/rails/actionwebservice/setup.rb +0 -1379
  150. data/vendor/rails/actionwebservice/test/abstract_client.rb +0 -183
  151. data/vendor/rails/actionwebservice/test/abstract_dispatcher.rb +0 -551
  152. data/vendor/rails/actionwebservice/test/abstract_unit.rb +0 -45
  153. data/vendor/rails/actionwebservice/test/api_test.rb +0 -102
  154. data/vendor/rails/actionwebservice/test/apis/auto_load_api.rb +0 -3
  155. data/vendor/rails/actionwebservice/test/apis/broken_auto_load_api.rb +0 -2
  156. data/vendor/rails/actionwebservice/test/base_test.rb +0 -42
  157. data/vendor/rails/actionwebservice/test/casting_test.rb +0 -86
  158. data/vendor/rails/actionwebservice/test/client_soap_test.rb +0 -153
  159. data/vendor/rails/actionwebservice/test/client_xmlrpc_test.rb +0 -152
  160. data/vendor/rails/actionwebservice/test/container_test.rb +0 -73
  161. data/vendor/rails/actionwebservice/test/dispatcher_action_controller_soap_test.rb +0 -137
  162. data/vendor/rails/actionwebservice/test/dispatcher_action_controller_xmlrpc_test.rb +0 -59
  163. data/vendor/rails/actionwebservice/test/fixtures/db_definitions/mysql.sql +0 -8
  164. data/vendor/rails/actionwebservice/test/fixtures/users.yml +0 -12
  165. data/vendor/rails/actionwebservice/test/gencov +0 -3
  166. data/vendor/rails/actionwebservice/test/invocation_test.rb +0 -185
  167. data/vendor/rails/actionwebservice/test/run +0 -6
  168. data/vendor/rails/actionwebservice/test/scaffolded_controller_test.rb +0 -146
  169. data/vendor/rails/actionwebservice/test/struct_test.rb +0 -52
  170. data/vendor/rails/actionwebservice/test/test_invoke_test.rb +0 -112
@@ -0,0 +1,2 @@
1
+ module GroupsHelper
2
+ end
@@ -1,5 +1,19 @@
1
1
  class Backlog < ActiveRecord::Base
2
- has_many :periods, :order => 'start_on', :dependent => :destroy
2
+ validates_presence_of :name
3
+ validates_length_of :name, :allow_nil => false, :maximum => 64
4
+ validates_inclusion_of :track_todo, :in => [true, false], :allow_nil => true, :message => ActiveRecord::Errors.default_error_messages[:blank]
5
+ validates_inclusion_of :track_done, :in => [true, false], :allow_nil => true, :message => ActiveRecord::Errors.default_error_messages[:blank]
6
+ validates_inclusion_of :track_times, :in => [true, false], :allow_nil => true, :message => ActiveRecord::Errors.default_error_messages[:blank]
7
+ validates_inclusion_of :enable_subtasks, :in => [true, false], :allow_nil => false, :message => ActiveRecord::Errors.default_error_messages[:blank]
8
+ validates_inclusion_of :enable_customer, :in => [true, false], :allow_nil => true, :message => ActiveRecord::Errors.default_error_messages[:blank]
9
+ validates_inclusion_of :enable_users, :in => [true, false], :allow_nil => true, :message => ActiveRecord::Errors.default_error_messages[:blank]
10
+ validates_length_of :invoice_code, :allow_nil => true, :maximum => 255
11
+
12
+ has_many :tasks, :order => 'period_id, position', :dependent => :destroy
13
+
14
+ def active_tasks
15
+ tasks.find(:all, :conditions => "finished_at IS NULL", :order => "position")
16
+ end
3
17
 
4
18
  def recent_tasks
5
19
  Task.find(:all, :conditions => "period_id = #{periods.first.id} AND (position IS NOT NULL OR finished_at >= '#{1.week.ago.iso8601}')", :order => "position, finished_at")
@@ -21,16 +35,11 @@ class Backlog < ActiveRecord::Base
21
35
  total
22
36
  end
23
37
 
24
- def required_speed
25
- return 0 if periods.empty?
26
- estimate_data(Date.today) / ((periods.last.end_on - Date.today).to_i > 0 ? (periods.last.end_on - Date.today).to_i : 1)
27
- end
28
-
29
38
  def first_active_period
30
- periods.each do |period|
31
- return period if period.active?
32
- end
33
- return periods.last
39
+ t = active_tasks
40
+ periods = t.map {|t| t.period}.uniq
41
+ periods = periods.select {|p| p.active?}
42
+ periods.sort_by {|p| p.end_on}.first
34
43
  end
35
44
 
36
45
  def enable_invoicing?
@@ -2,8 +2,9 @@ class Estimate < ActiveRecord::Base
2
2
  belongs_to :task
3
3
  belongs_to :user
4
4
 
5
+ validates_associated :task
6
+
5
7
  def after_create
6
- puts todo
7
8
  task.finish(Task::COMPLETED, false, user) if todo == 0
8
9
  end
9
10
 
@@ -0,0 +1,11 @@
1
+ #class Group < ActiveRecord::Base
2
+ class Group < Party
3
+ class_table_inheritance
4
+
5
+ # TODO (uwe): We need to specify :join_table, :foreign_key and :association_foreign_key
6
+ # even if they follow the defaults since ClassTableInheritanceInRails breaks it.
7
+ has_and_belongs_to_many :users, :join_table => "groups_users", :foreign_key => "group_id", :association_foreign_key => 'user_id'
8
+
9
+ validates_presence_of :name
10
+ validates_length_of :name, :allow_nil => false, :maximum => 255
11
+ end
@@ -0,0 +1,3 @@
1
+ class Party < ActiveRecord::Base
2
+ has_many :periods, :order => :position, :dependent => :destroy
3
+ end
@@ -1,7 +1,17 @@
1
1
  class Period < ActiveRecord::Base
2
- belongs_to :backlog
3
- acts_as_list :scope => :backlog
2
+ belongs_to :party
3
+ acts_as_list :scope => :party, :order => :position
4
4
  has_many :tasks, :order => 'position, finished_at', :dependent => :destroy
5
+ validates_associated :party
6
+ validates_uniqueness_of :position, :scope => :party_id
7
+
8
+ def validate
9
+ errors.add "A period cannot end before it starts" unless end_on >= start_on
10
+ end
11
+
12
+ def self.find_active_or_future
13
+ find(:all, :conditions => "end_on >= '#{Date.today.strftime '%Y-%m-%d'}'")
14
+ end
5
15
 
6
16
  def completed_tasks
7
17
  tasks.select {|task| task.completed?}
@@ -11,6 +21,17 @@ class Period < ActiveRecord::Base
11
21
  tasks.select {|task| task.active?}
12
22
  end
13
23
 
24
+ def most_frequent_backlog
25
+ all_backlogs = tasks.map {|t| t.backlog}.compact
26
+ return nil if all_backlogs.empty?
27
+ freq = {}
28
+ all_backlogs.each do |b|
29
+ freq[b.id] ||= 0
30
+ freq[b.id] += 1
31
+ end
32
+ freq.to_a.sort_by {|backlog, count| count}.first[0]
33
+ end
34
+
14
35
  def active?(check_tasks = false)
15
36
  start_on <= Date.today && (end_on >= Date.today || (check_tasks && tasks.select {|task| task.active?}.size > 0))
16
37
  end
@@ -58,7 +79,11 @@ class Period < ActiveRecord::Base
58
79
  end
59
80
 
60
81
  def to_s
61
- "#{backlog.name}##{position}"
82
+ name
83
+ end
84
+
85
+ def name
86
+ "#{party.name}##{position}"
62
87
  end
63
88
 
64
89
  def dates
@@ -109,16 +134,28 @@ class Period < ActiveRecord::Base
109
134
  by_line
110
135
  end
111
136
 
137
+ def estimates?
138
+ not backlogs.find {|backlog| backlog.track_todo?}.nil?
139
+ end
140
+
141
+ def track_work?
142
+ not backlogs.find {|backlog| backlog.track_done?}.nil?
143
+ end
144
+
112
145
  def track_times?
113
- backlog.track_times?
146
+ not backlogs.find {|backlog| backlog.track_times?}.nil?
114
147
  end
115
148
 
116
149
  def enable_subtasks?
117
- backlog.enable_subtasks?
150
+ not backlogs.find {|backlog| backlog.enable_subtasks?}.nil?
118
151
  end
119
152
 
120
153
  def invoice?
121
- backlog.enable_invoicing?
154
+ not backlogs.find {|backlog| backlog.enable_invoicing?}.nil?
155
+ end
156
+
157
+ def backlogs
158
+ tasks.map {|task| task.backlog}.uniq
122
159
  end
123
160
 
124
161
  end
@@ -1,8 +1,10 @@
1
1
  class Task < ActiveRecord::Base
2
2
  COMPLETED = 'COMPLETED'
3
3
  POSTPONED = 'POSTPONED'
4
+ MOVED = 'MOVED'
4
5
  ABORTED = 'ABORTED'
5
6
 
7
+ belongs_to :backlog
6
8
  belongs_to :period
7
9
  acts_as_list :scope => '#{period_id ? "period_id = #{period_id}" : "parent_id = #{parent_id}"} AND finished_at IS NULL'
8
10
  has_many :estimates, :order => 'created_at', :dependent => :destroy
@@ -11,7 +13,8 @@ class Task < ActiveRecord::Base
11
13
 
12
14
  validates_size_of :description, :maximum => 80
13
15
  validates_size_of :customer, :maximum => 64, :if => :customer
14
- # validates_presence_of :created_at
16
+ validates_presence_of :backlog_id, :if => Proc.new { |task| task.parent_id.nil? }
17
+ validates_presence_of :parent_id, :if => Proc.new { |task| task.backlog_id.nil? }
15
18
  validates_uniqueness_of :description, :scope => :period_id
16
19
 
17
20
  def validate
@@ -23,6 +26,10 @@ class Task < ActiveRecord::Base
23
26
  end
24
27
  end
25
28
 
29
+ def self.find_open
30
+ find(:all, :conditions => 'finished_at IS NULL', :order => 'description')
31
+ end
32
+
26
33
  def self.find_started(user)
27
34
  if user
28
35
  user_clause = " OR user_id = #{user.id}"
@@ -31,10 +38,6 @@ class Task < ActiveRecord::Base
31
38
  Work.find(:all, :conditions => conditions).map {|work| work.task}
32
39
  end
33
40
 
34
- def self.open_conditions
35
- return "finished_at IS NULL"
36
- end
37
-
38
41
  def self.recent_conditions
39
42
  return "finished_at >= '#{1.week.ago.iso8601}'"
40
43
  end
@@ -112,14 +115,20 @@ class Task < ActiveRecord::Base
112
115
  raise "Period missing" unless period
113
116
  raise "Cannot move finished tasks" unless active?
114
117
 
115
- new_task = Task.find_by_period_id_and_previous_task_id(period.id, self.id) || Task.new
116
- new_task.description = self.description
118
+ ancestor_id = self.previous_task_id || self.id
119
+ new_task = Task.find_by_period_id_and_id(period.id, ancestor_id)
120
+ new_task ||= Task.find_by_period_id_and_previous_task_id(period.id, ancestor_id)
121
+ new_task ||= Task.new
122
+ new_task.open(user)
123
+ new_task.previous_task_id = self.previous_task_id || self.id
124
+ new_task.backlog = backlog
117
125
  new_task.period = period
118
- new_task.previous_task_id = self.id
126
+ new_task.description = self.description
119
127
  new_task.save!
128
+ new_task.estimate(self.todo, user)
120
129
  new_task.move_to_top
121
130
  new_task.estimate(self.todo, user)
122
- self.finish(Task::POSTPONED, true, user)
131
+ self.finish(new_task.period.party == self.period.party ? Task::POSTPONED : Task::MOVED, true, user)
123
132
  end
124
133
 
125
134
  def finish(resolution, save_work, user)
@@ -172,24 +181,28 @@ class Task < ActiveRecord::Base
172
181
 
173
182
  def root_task
174
183
  root_task = self
175
- root_task = root_task.parent while !root_task.root?
184
+ root_task = root_task.parent while root_task.parent
176
185
  root_task
177
186
  end
178
187
 
179
188
  def track_done?
180
- root_task.period.backlog.track_done
189
+ root_task.backlog.track_done
181
190
  end
182
191
 
183
192
  def track_times?
184
- root_task.period.backlog.track_times
193
+ root_task.backlog.track_times?
185
194
  end
186
195
 
187
196
  def track_todo?
188
- root_task.period.backlog.track_todo
197
+ root_task.backlog.track_todo?
189
198
  end
190
199
 
191
200
  def enable_subtasks?
192
- root_task.period.backlog.enable_subtasks
201
+ root_task.backlog.enable_subtasks?
202
+ end
203
+
204
+ def enable_customer?
205
+ root_task.backlog.enable_customer?
193
206
  end
194
207
 
195
208
  alias_method :old_period, :period
@@ -1,7 +1,14 @@
1
1
  require 'digest/sha1'
2
2
 
3
3
  # this model expects a certain database layout and its based on the name/login pattern.
4
- class User < ActiveRecord::Base
4
+ #class User < ActiveRecord::Base
5
+ class User < Party
6
+ class_table_inheritance
7
+
8
+ # TODO (uwe): We need to specify :join_table, :foreign_key and :association_foreign_key
9
+ # even if they follow the defaults since ClassTableInheritanceInRails breaks it.
10
+ has_and_belongs_to_many :groups, :join_table => "groups_users", :foreign_key => "user_id", :association_foreign_key => 'group_id'
11
+
5
12
  attr_accessor :password_needs_confirmation
6
13
 
7
14
  after_save '@password_needs_confirmation = false'
@@ -9,14 +16,31 @@ class User < ActiveRecord::Base
9
16
 
10
17
  validates_presence_of :login, :on => :create
11
18
  validates_length_of :login, :within => 3..40, :on => :create
12
- validates_uniqueness_of :login, :on => :create
13
- validates_uniqueness_of :email, :on => :create
14
-
19
+
20
+ # TODO (uwe): This is commented out since it is broken by ClassTableInheritanceInRails
21
+ #validates_uniqueness_of :login, :on => :create
22
+
23
+ validates_presence_of :email
24
+ validates_length_of :email, :allow_nil => false, :maximum => 60, :if => :email
25
+
26
+ # TODO (uwe): This is commented out since it is broken by ClassTableInheritanceInRails
27
+ #validates_uniqueness_of :email, :on => :create
28
+
29
+ # This is commented out since I want to allow empty passwords
15
30
  # validates_presence_of :password, :if => :validate_password?
16
31
  validates_confirmation_of :password, :if => :validate_password?
32
+ # This is commented out since I want to allow empty passwords
17
33
  # validates_length_of :password, { :minimum => 5, :if => :validate_password? }
18
34
  validates_length_of :password, { :maximum => 40, :if => :validate_password? }
19
35
 
36
+ validates_length_of :first_name, :allow_nil => true, :maximum => 40
37
+ validates_length_of :last_name, :allow_nil => true, :maximum => 40
38
+
39
+ validates_length_of :role, :allow_nil => true, :maximum => 40
40
+
41
+ validates_length_of :security_token, :allow_nil => true, :maximum => 40
42
+ validates_inclusion_of :deleted, :in => [true, false], :allow_nil => true, :message => ActiveRecord::Errors.default_error_messages[:blank]
43
+
20
44
  def initialize(attributes = nil)
21
45
  super
22
46
  @password_needs_confirmation = false
@@ -66,6 +90,9 @@ class User < ActiveRecord::Base
66
90
  UserSystem::CONFIG[:security_token_life_hours] * 60 * 60
67
91
  end
68
92
 
93
+ def name
94
+ [first_name, last_name].compact.join(' ')
95
+ end
69
96
 
70
97
  protected
71
98
 
@@ -76,7 +103,8 @@ class User < ActiveRecord::Base
76
103
  end
77
104
 
78
105
  def self.hashed(str)
79
- return Digest::SHA1.hexdigest("change-me--#{str}--")[0..39]
106
+ hashed_password = Digest::SHA1.hexdigest("change-me--#{str}--")[0..39]
107
+ return hashed_password
80
108
  end
81
109
 
82
110
  def crypt_password
@@ -90,12 +118,13 @@ class User < ActiveRecord::Base
90
118
  expiry = Time.at(Clock.now.to_i + token_lifetime)
91
119
  write_attribute('security_token', self.class.hashed(self.salted_password + Clock.now.to_i.to_s + rand.to_s))
92
120
  write_attribute('token_expiry', expiry)
93
- update_without_callbacks
121
+ # update_without_callbacks
122
+ update
94
123
  return self.security_token
95
124
  end
96
125
 
97
126
  def self.salted_password(salt, hashed_password)
98
- hashed(salt + hashed_password)
127
+ salted_password = hashed(salt + hashed_password)
128
+ return salted_password
99
129
  end
100
130
  end
101
-
@@ -6,11 +6,11 @@ class Work < ActiveRecord::Base
6
6
  validates_presence_of :user_id, :if => :validate_user?
7
7
 
8
8
  def validate_user?
9
- task.period.backlog.enable_users
9
+ task.backlog.enable_users
10
10
  end
11
11
 
12
12
  def track_times?
13
- task.period.backlog.track_times?
13
+ task.backlog.track_times?
14
14
  end
15
15
 
16
16
  # Return an array with an array of works per day:
@@ -26,7 +26,7 @@ class Work < ActiveRecord::Base
26
26
  works = find(:all, :conditions => "completed_at BETWEEN '#{first.to_time.iso8601}' AND '#{last.to_time.iso8601}'", :order => 'completed_at')
27
27
  length = 0
28
28
  works_per_day = (0..6).map do |day|
29
- works_for_day = works.select {|work| work.completed_at.to_date == (first + day) && (!work.task.period.backlog.enable_users || (user && work.user_id == user.id)) }
29
+ works_for_day = works.select {|work| work.completed_at.to_date == (first + day) && (!work.task.backlog.enable_users || (user && work.user_id == user.id)) }
30
30
  length = [length, works_for_day.length].max
31
31
  works_for_day
32
32
  end
@@ -47,8 +47,7 @@ class Work < ActiveRecord::Base
47
47
  Backlog.find(:all).each do |backlog|
48
48
  totals_per_backlog[backlog.id] = [[], []]
49
49
  (0..6).each do |day|
50
- works_for_day = works.select {|work| work.task.period.backlog == backlog && work.completed_at.to_date == (first + day) && (!work.task.period.backlog.enable_users || (user_id && work.user_id == user_id)) }
51
- p works_for_day
50
+ works_for_day = works.select {|work| work.task.backlog == backlog && work.completed_at.to_date == (first + day) && (!work.task.backlog.enable_users || (user_id && work.user_id == user_id)) }
52
51
  invoice_works_for_day = works_for_day.select {|work| work.invoice? }
53
52
  internal_works_for_day = works_for_day.select {|work| !work.invoice? }
54
53
 
@@ -61,7 +60,6 @@ class Work < ActiveRecord::Base
61
60
  totals_per_backlog.reject! do |backlog_id, day_totals|
62
61
  !day_totals[0].find{|day_total| day_total > 0} && !day_totals[1].find{|day_total| day_total > 0}
63
62
  end
64
- p totals_per_backlog
65
63
  totals_per_backlog
66
64
  end
67
65
 
@@ -0,0 +1,5 @@
1
+ <ul class="backlogs">
2
+ <% for backlog in @backlogs do -%>
3
+ <li class="task"><div class="name"><%=h backlog.name %></div></li>
4
+ <% end -%>
5
+ </ul>
@@ -55,15 +55,15 @@ function handle<%=@task.id%>(field, event) {
55
55
  <% end %>
56
56
  <td>
57
57
  <% unless @task.finished_at %>
58
- <%= image_button_to '/images/arrow07_4', l(:up), :controller => 'tasks', :action => :move_up, :id => @task %>
58
+ <%= image_button_to 'arrow07_4.png', l(:up), :controller => 'tasks', :action => :move_up, :id => @task %>
59
59
  </td>
60
60
  <td>
61
- <%= image_button_to('/images/arrow07_2', l(:down), :controller => 'tasks', :action => :move_down, :id => @task)%>
61
+ <%= image_button_to('arrow07_2.png', l(:down), :controller => 'tasks', :action => :move_down, :id => @task)%>
62
62
  </td>
63
63
  <td>
64
- <%= image_button_to('/images/checkmark_joel_montes_de_', l(:complete), :controller => 'tasks', :action => :finish, :id => @task)%>
64
+ <%= image_button_to('checkmark_joel_montes_de_.png', l(:complete), :controller => 'tasks', :action => :finish, :id => @task)%>
65
65
  <% else %>
66
- <%=image_button_to('/images/eraser', l(:reopen), :controller => 'tasks', :action => :reopen, :id => @task) %>
66
+ <%=image_button_to('eraser.png', l(:reopen), :controller => 'tasks', :action => :reopen, :id => @task) %>
67
67
  <% end %>
68
68
  </td>
69
69
  </tr>
@@ -0,0 +1,7 @@
1
+ <%= error_messages_for 'group' %>
2
+
3
+ <!--[form:group]-->
4
+ <p><label for="group_name"><%=l :name%></label><br/>
5
+ <%= text_field 'group', 'name' %></p>
6
+ <!--[eoform:group]-->
7
+
@@ -0,0 +1,31 @@
1
+ <div id="spotlight">
2
+ <% @page_title = "#{l :editing} #{l :group}" %>
3
+
4
+ <% form_tag :action => 'update', :id => @group do %>
5
+ <%= render :partial => 'form' %>
6
+ <%= submit_tag l(:save) %>
7
+ <%= back_or_link_to l(:back), :action => 'list' %>
8
+ <% end %>
9
+ </div>
10
+
11
+ <div id="lfeature">
12
+ <div class="btitle">
13
+ <h4><%=l :members %></h4>
14
+ </div>
15
+
16
+ <table>
17
+ <% for @user in @users %>
18
+ <tr>
19
+ <td><%=h @user.name%></td>
20
+ <td>
21
+ <% form_for :group, @group, :url => {:action => :set_member, :id => @group, :user_id => @user.id} do %>
22
+ <%=check_box_tag :value, true, @group.users.include?(@user), :onchange => "form.submit()" %></td>
23
+ <% end %>
24
+ </tr>
25
+ <% end %>
26
+ </table>
27
+
28
+ <%= back_or_link_to l(:back), :action => 'list' %>
29
+
30
+ </div>
31
+