backlog 0.0.4 → 0.0.5

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