backlog 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +10 -0
- data/Rakefile +2 -1
- data/app/controllers/application.rb +55 -8
- data/app/controllers/groups_controller.rb +62 -0
- data/app/controllers/periods_controller.rb +13 -55
- data/app/controllers/tasks_controller.rb +9 -5
- data/app/controllers/works_controller.rb +43 -6
- data/app/helpers/application_helper.rb +20 -2
- data/app/helpers/groups_helper.rb +2 -0
- data/app/models/backlog.rb +19 -10
- data/app/models/estimate.rb +2 -1
- data/app/models/group.rb +11 -0
- data/app/models/party.rb +3 -0
- data/app/models/period.rb +43 -6
- data/app/models/task.rb +27 -14
- data/app/models/user.rb +37 -8
- data/app/models/work.rb +4 -6
- data/app/views/backlogs/_name_list.rhtml +5 -0
- data/app/views/backlogs/show.rhtml +4 -4
- data/app/views/groups/_form.rhtml +7 -0
- data/app/views/groups/edit.rhtml +31 -0
- data/app/views/groups/list.rhtml +27 -0
- data/app/views/groups/new.rhtml +8 -0
- data/app/views/layouts/wide.rhtml +2 -2
- data/app/views/periods/_burn_down_chart.rhtml +1 -1
- data/app/views/periods/_form.rhtml +13 -9
- data/app/views/periods/_show_active.rhtml +6 -12
- data/app/views/periods/_title.rhtml +4 -5
- data/app/views/periods/edit.rhtml +1 -1
- data/app/views/periods/new.rhtml +1 -1
- data/app/views/periods/show.rhtml +10 -6
- data/app/views/tasks/_backlog_header.rhtml +22 -0
- data/app/views/tasks/_description_list.rhtml +5 -0
- data/app/views/tasks/_form.rhtml +26 -7
- data/app/views/tasks/_task.rhtml +4 -4
- data/app/views/tasks/edit.rhtml +2 -3
- data/app/views/tasks/list_started.rhtml +1 -0
- data/app/views/tasks/new.rhtml +2 -2
- data/app/views/works/_buttons.rhtml +3 -0
- data/app/views/works/_form.rhtml +15 -10
- data/app/views/works/daily_work_sheet.rhtml +30 -18
- data/app/views/works/edit.rhtml +4 -4
- data/app/views/works/list.rhtml +2 -2
- data/app/views/works/new.rhtml +3 -2
- data/app/views/works/weekly_work_sheet.rhtml +2 -2
- data/bin/backlog +2 -0
- data/bin/backlog_init.d_kubosch_production +27 -0
- data/bin/copy_production2development.rb +33 -0
- data/config/database.yml +13 -7
- data/config/deploy_kubosch.rb +1 -0
- data/config/environment.rb +2 -0
- data/config/environments/development_mysql.rb +27 -0
- data/config/environments/kubosch_production_mysql.rb +21 -0
- data/config/routes.rb +1 -1
- data/db/migrate/{001_tasks.rb → 001_create_tasks.rb} +1 -1
- data/db/migrate/{002_backlogs.rb → 002_create_backlogs.rb} +2 -2
- data/db/migrate/003_add_estimation_points.rb +1 -1
- data/db/migrate/004_add_period.rb +2 -2
- data/db/migrate/013_create_estimates.rb +1 -1
- data/db/migrate/015_add_user_option.rb +9 -5
- data/db/migrate/017_insert_datek_projects.rb +13 -10
- data/db/migrate/018_create_groups.rb +115 -0
- data/db/schema.rb +72 -12
- data/lang/en.yaml +7 -0
- data/lang/no.yaml +7 -0
- data/lib/big_decimal_yaml_fix.rb +27 -0
- data/lib/class_table_inheritance.rb +163 -0
- data/lib/tasks/backup.rake +92 -0
- data/public/images/person.org.png +0 -0
- data/public/images/person.png +0 -0
- data/public/stylesheets/backlog.css +3 -1
- data/public/stylesheets/mwrt002.css +1 -1
- data/test/fixtures/groups.yml +6 -0
- data/test/fixtures/parties.yml +31 -0
- data/test/fixtures/periods.yml +2 -2
- data/test/fixtures/tasks.yml +2 -0
- data/test/fixtures/users.yml +6 -6
- data/test/functional/backlogs_controller_test.rb +1 -1
- data/test/functional/groups_controller_test.rb +120 -0
- data/test/functional/periods_controller_test.rb +1 -1
- data/test/functional/tasks_controller_test.rb +16 -1
- data/test/functional/user_controller_test.rb +8 -2
- data/test/test_helper.rb +5 -0
- data/test/unit/big_decimal_yaml_fix_test.rb +14 -0
- data/test/unit/estimate_test.rb +1 -1
- data/test/unit/group_test.rb +10 -0
- data/test/unit/user_test.rb +56 -44
- data/tmp/sessions/ruby_sess.22dec3e9df47fb4e +0 -0
- data/tmp/sessions/ruby_sess.8037e0ab58cbcf1a +0 -0
- data/vendor/plugins/activerecord_foreign_key_extensions/lib/active_record_extensions.rb +35 -0
- data/vendor/rails/actionmailer/test/fixtures/test_mailer/implicitly_multipart_example.rhtml.bak +1 -0
- data/vendor/rails/{actionwebservice/lib/action_web_service/templates/scaffolds/layout.rhtml → railties/configs/empty.log} +0 -0
- metadata +36 -105
- data/backlog.gemspec +0 -21
- data/vendor/rails/actionwebservice/CHANGELOG +0 -265
- data/vendor/rails/actionwebservice/MIT-LICENSE +0 -21
- data/vendor/rails/actionwebservice/README +0 -364
- data/vendor/rails/actionwebservice/Rakefile +0 -171
- data/vendor/rails/actionwebservice/TODO +0 -32
- data/vendor/rails/actionwebservice/examples/googlesearch/README +0 -143
- data/vendor/rails/actionwebservice/examples/googlesearch/autoloading/google_search_api.rb +0 -50
- data/vendor/rails/actionwebservice/examples/googlesearch/autoloading/google_search_controller.rb +0 -57
- data/vendor/rails/actionwebservice/examples/googlesearch/delegated/google_search_service.rb +0 -108
- data/vendor/rails/actionwebservice/examples/googlesearch/delegated/search_controller.rb +0 -7
- data/vendor/rails/actionwebservice/examples/googlesearch/direct/google_search_api.rb +0 -50
- data/vendor/rails/actionwebservice/examples/googlesearch/direct/search_controller.rb +0 -58
- data/vendor/rails/actionwebservice/examples/metaWeblog/README +0 -17
- data/vendor/rails/actionwebservice/examples/metaWeblog/apis/blogger_api.rb +0 -60
- data/vendor/rails/actionwebservice/examples/metaWeblog/apis/blogger_service.rb +0 -34
- data/vendor/rails/actionwebservice/examples/metaWeblog/apis/meta_weblog_api.rb +0 -67
- data/vendor/rails/actionwebservice/examples/metaWeblog/apis/meta_weblog_service.rb +0 -48
- data/vendor/rails/actionwebservice/examples/metaWeblog/controllers/xmlrpc_controller.rb +0 -16
- data/vendor/rails/actionwebservice/install.rb +0 -30
- data/vendor/rails/actionwebservice/lib/action_web_service.rb +0 -66
- data/vendor/rails/actionwebservice/lib/action_web_service/api.rb +0 -301
- data/vendor/rails/actionwebservice/lib/action_web_service/base.rb +0 -42
- data/vendor/rails/actionwebservice/lib/action_web_service/casting.rb +0 -138
- data/vendor/rails/actionwebservice/lib/action_web_service/client.rb +0 -3
- data/vendor/rails/actionwebservice/lib/action_web_service/client/base.rb +0 -28
- data/vendor/rails/actionwebservice/lib/action_web_service/client/soap_client.rb +0 -113
- data/vendor/rails/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb +0 -58
- data/vendor/rails/actionwebservice/lib/action_web_service/container.rb +0 -3
- data/vendor/rails/actionwebservice/lib/action_web_service/container/action_controller_container.rb +0 -93
- data/vendor/rails/actionwebservice/lib/action_web_service/container/delegated_container.rb +0 -86
- data/vendor/rails/actionwebservice/lib/action_web_service/container/direct_container.rb +0 -69
- data/vendor/rails/actionwebservice/lib/action_web_service/dispatcher.rb +0 -2
- data/vendor/rails/actionwebservice/lib/action_web_service/dispatcher/abstract.rb +0 -207
- data/vendor/rails/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +0 -379
- data/vendor/rails/actionwebservice/lib/action_web_service/invocation.rb +0 -202
- data/vendor/rails/actionwebservice/lib/action_web_service/protocol.rb +0 -4
- data/vendor/rails/actionwebservice/lib/action_web_service/protocol/abstract.rb +0 -112
- data/vendor/rails/actionwebservice/lib/action_web_service/protocol/discovery.rb +0 -37
- data/vendor/rails/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb +0 -176
- data/vendor/rails/actionwebservice/lib/action_web_service/protocol/soap_protocol/marshaler.rb +0 -235
- data/vendor/rails/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb +0 -122
- data/vendor/rails/actionwebservice/lib/action_web_service/scaffolding.rb +0 -283
- data/vendor/rails/actionwebservice/lib/action_web_service/struct.rb +0 -68
- data/vendor/rails/actionwebservice/lib/action_web_service/support/class_inheritable_options.rb +0 -26
- data/vendor/rails/actionwebservice/lib/action_web_service/support/signature_types.rb +0 -226
- data/vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/layout.erb +0 -65
- data/vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/methods.erb +0 -6
- data/vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/methods.rhtml +0 -0
- data/vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.erb +0 -29
- data/vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml +0 -0
- data/vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/result.erb +0 -30
- data/vendor/rails/actionwebservice/lib/action_web_service/templates/scaffolds/result.rhtml +0 -0
- data/vendor/rails/actionwebservice/lib/action_web_service/test_invoke.rb +0 -110
- data/vendor/rails/actionwebservice/lib/action_web_service/version.rb +0 -9
- data/vendor/rails/actionwebservice/setup.rb +0 -1379
- data/vendor/rails/actionwebservice/test/abstract_client.rb +0 -183
- data/vendor/rails/actionwebservice/test/abstract_dispatcher.rb +0 -551
- data/vendor/rails/actionwebservice/test/abstract_unit.rb +0 -45
- data/vendor/rails/actionwebservice/test/api_test.rb +0 -102
- data/vendor/rails/actionwebservice/test/apis/auto_load_api.rb +0 -3
- data/vendor/rails/actionwebservice/test/apis/broken_auto_load_api.rb +0 -2
- data/vendor/rails/actionwebservice/test/base_test.rb +0 -42
- data/vendor/rails/actionwebservice/test/casting_test.rb +0 -86
- data/vendor/rails/actionwebservice/test/client_soap_test.rb +0 -153
- data/vendor/rails/actionwebservice/test/client_xmlrpc_test.rb +0 -152
- data/vendor/rails/actionwebservice/test/container_test.rb +0 -73
- data/vendor/rails/actionwebservice/test/dispatcher_action_controller_soap_test.rb +0 -137
- data/vendor/rails/actionwebservice/test/dispatcher_action_controller_xmlrpc_test.rb +0 -59
- data/vendor/rails/actionwebservice/test/fixtures/db_definitions/mysql.sql +0 -8
- data/vendor/rails/actionwebservice/test/fixtures/users.yml +0 -12
- data/vendor/rails/actionwebservice/test/gencov +0 -3
- data/vendor/rails/actionwebservice/test/invocation_test.rb +0 -185
- data/vendor/rails/actionwebservice/test/run +0 -6
- data/vendor/rails/actionwebservice/test/scaffolded_controller_test.rb +0 -146
- data/vendor/rails/actionwebservice/test/struct_test.rb +0 -52
- data/vendor/rails/actionwebservice/test/test_invoke_test.rb +0 -112
data/app/models/backlog.rb
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
class Backlog < ActiveRecord::Base
|
2
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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?
|
data/app/models/estimate.rb
CHANGED
data/app/models/group.rb
ADDED
@@ -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
|
data/app/models/party.rb
ADDED
data/app/models/period.rb
CHANGED
@@ -1,7 +1,17 @@
|
|
1
1
|
class Period < ActiveRecord::Base
|
2
|
-
belongs_to :
|
3
|
-
acts_as_list :scope => :
|
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
|
-
|
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
|
data/app/models/task.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
116
|
-
new_task
|
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.
|
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
|
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.
|
189
|
+
root_task.backlog.track_done
|
181
190
|
end
|
182
191
|
|
183
192
|
def track_times?
|
184
|
-
root_task.
|
193
|
+
root_task.backlog.track_times?
|
185
194
|
end
|
186
195
|
|
187
196
|
def track_todo?
|
188
|
-
root_task.
|
197
|
+
root_task.backlog.track_todo?
|
189
198
|
end
|
190
199
|
|
191
200
|
def enable_subtasks?
|
192
|
-
root_task.
|
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
|
data/app/models/user.rb
CHANGED
@@ -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
|
-
|
13
|
-
|
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
|
-
|
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
|
-
|
data/app/models/work.rb
CHANGED
@@ -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.
|
9
|
+
task.backlog.enable_users
|
10
10
|
end
|
11
11
|
|
12
12
|
def track_times?
|
13
|
-
task.
|
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.
|
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.
|
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
|
|
@@ -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 '
|
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('
|
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('
|
64
|
+
<%= image_button_to('checkmark_joel_montes_de_.png', l(:complete), :controller => 'tasks', :action => :finish, :id => @task)%>
|
65
65
|
<% else %>
|
66
|
-
<%=image_button_to('
|
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,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
|
+
|