backlog 0.3.2 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,8 @@
1
+ == 0.3.3 2007-08-03
2
+
3
+ * Made validation of tasks position tighter
4
+ * Fixed bugs in task positioning :)
5
+
1
6
  == 0.3.2 2007-08-02
2
7
 
3
8
  * Improved setup on linux
data/README.txt CHANGED
@@ -5,6 +5,12 @@ Welcome to Backlog!
5
5
  Backlog is a tool to help you collect and organize all your tasks,
6
6
  wether you are a single persion or a small or large group.
7
7
 
8
+ A timekeeping module is also included to track time spent on the different tasks.
9
+
10
+ === Backlog is not meant to be
11
+
12
+ * an issue tracker with customer communication.
13
+
8
14
  === Installation
9
15
 
10
16
  * Install ruby
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ require 'tasks/rails'
11
11
 
12
12
  require 'hoe'
13
13
 
14
- Hoe.new("backlog", '0.3.2') do |p|
14
+ Hoe.new("backlog", '0.3.3') do |p|
15
15
  p.rubyforge_name = "backlog"
16
16
  p.summary = "Application to aid collecting, processing, organizing, reviewing and doing tasks."
17
17
  p.description = p.paragraphs_of('README.txt', 0..-1).join("\n\n")
@@ -1,6 +1,5 @@
1
1
  class TasksController < ApplicationController
2
- skip_before_filter :populate_layout, :only => [:create, :update, :set_task_description, :move_to,
3
- :move_to_next_period, :move_to_period, :reopen, :start_work]
2
+ skip_before_filter :populate_layout, :only => [:create, :update, :destroy, :set_task_description, :move_to, :move_to_next_period, :move_to_period, :reopen, :start_work]
4
3
 
5
4
  verify :method => :post, :except => [ :new, :show, :edit, :list_started, :move_to_next_period],
6
5
  :redirect_to => { :controller => 'backlogs' }
@@ -28,7 +27,11 @@ class TasksController < ApplicationController
28
27
  if @task.save
29
28
  flash[:notice] = 'Task was successfully created.'
30
29
  @task.move_to_top
31
- redirect_to :controller => 'periods', :action => 'show', :id => @task.period, :task => @task.id
30
+ if @task.period
31
+ back_or_redirect_to :controller => 'periods', :action => 'show', :id => @task.period, :task => @task.id
32
+ else
33
+ back_or_redirect_to :controller => 'backlogs', :action => 'show', :id => @task.backlog, :task => @task.id
34
+ end
32
35
  else
33
36
  populate_layout
34
37
  @backlogs = Backlog.find(:all, :order => 'name')
@@ -75,6 +78,7 @@ class TasksController < ApplicationController
75
78
  end
76
79
  else
77
80
  populate_layout
81
+ edit
78
82
  render :action => 'edit'
79
83
  end
80
84
  end
@@ -146,7 +150,7 @@ class TasksController < ApplicationController
146
150
 
147
151
  def finish
148
152
  @task = Task.find(params[:id])
149
- @task.finish(Task::COMPLETED, true, user)
153
+ @task.finish(Task::COMPLETED, true)
150
154
  redirect_to :controller => 'periods', :action => :show, :id => @task.period, :task_id => @task.id
151
155
  end
152
156
 
@@ -158,14 +162,13 @@ class TasksController < ApplicationController
158
162
 
159
163
  def reopen
160
164
  task = Task.find(params[:id])
161
- task.reopen(user)
165
+ task.reopen
162
166
  back_or_redirect_to :controller => 'periods', :action => :show, :id => task.period, :task => task.id
163
167
  end
164
168
 
165
169
  def start_work
166
170
  task = Task.find(params[:id])
167
- task.start_work(user)
168
- task.save!
171
+ task.start_work
169
172
  redirect_to :controller => 'periods', :action => :show, :id => task.period, :task => task.id
170
173
  end
171
174
 
@@ -42,7 +42,7 @@ class WorksController < ApplicationController
42
42
  return
43
43
  end
44
44
 
45
- @work.task.estimates.new(params[:estimate]).save! if params[:estimate]
45
+ @work.task.estimates.create!(params[:estimate]) if params[:estimate]
46
46
 
47
47
  back_or_redirect_to :controller => 'periods', :action => 'show', :id => @work.task.period, :task_id => @work.task.id
48
48
  end
@@ -61,11 +61,14 @@ class WorksController < ApplicationController
61
61
  convert_hours_param
62
62
  if @work.update_attributes(params[:work])
63
63
  flash[:notice] = 'Work was successfully updated.'
64
- back_or_redirect_to :controller => 'periods', :action => 'show', :id => @work.task.period, :task_id => @work.task.id
65
- else
66
- render :action => 'edit'
64
+ if params[:estimate].nil? || (@estimate = @work.task.estimates.create(params[:estimate])).errors.size == 0
65
+ back_or_redirect_to :controller => 'periods', :action => 'show', :id => @work.task.period, :task_id => @work.task.id
66
+ return
67
+ end
67
68
  end
68
- @work.task.estimates.new(params[:estimate]).save! if params[:estimate]
69
+ @task = @work.task
70
+ edit
71
+ render :action => 'edit'
69
72
  end
70
73
 
71
74
  def destroy
@@ -102,7 +105,7 @@ class WorksController < ApplicationController
102
105
 
103
106
  def auto_complete_for_work_backlog_name
104
107
  @backlogs = Backlog.find(:all,
105
- :conditions => [ 'LOWER(name) LIKE ?',
108
+ :conditions => [ 'LOWER(name) LIKE ?',
106
109
  '%' + params[:work][:backlog_name].downcase + '%' ],
107
110
  :order => 'name ASC',
108
111
  :limit => 16)
@@ -37,7 +37,7 @@ class Backlog < ActiveRecord::Base
37
37
 
38
38
  def first_active_period
39
39
  t = active_tasks
40
- periods = t.map {|t| t.period}.uniq
40
+ periods = t.map {|t| t.period}.compact.uniq
41
41
  periods = periods.select {|p| p.active?}
42
42
  periods.sort_by {|p| p.end_on}.first
43
43
  end
@@ -10,7 +10,7 @@ class Estimate < ActiveRecord::Base
10
10
  validates_associated :task
11
11
 
12
12
  def after_create
13
- task.finish(Task::COMPLETED, false, user) if todo == 0
13
+ task.finish(Task::COMPLETED, false) if todo == 0
14
14
  end
15
15
 
16
16
  end
data/app/models/task.rb CHANGED
@@ -8,7 +8,7 @@ class Task < ActiveRecord::Base
8
8
 
9
9
  belongs_to :backlog
10
10
  belongs_to :period
11
- acts_as_list :scope => '#{period_id ? "period_id = #{period_id}" : "parent_id = #{parent_id}"} AND finished_at IS NULL'
11
+ acts_as_list :scope => '#{period_id ? "period_id = #{period_id}" : parent_id ? "parent_id = #{parent_id}" : "backlog_id = #{backlog_id}"} AND finished_at IS NULL'
12
12
  has_many :estimates, :order => 'created_at', :dependent => :destroy
13
13
  has_many :works, :order => 'completed_at', :dependent => :destroy
14
14
  acts_as_tree :order => 'position'
@@ -20,12 +20,15 @@ class Task < ActiveRecord::Base
20
20
  #validates_absence_of :position, :if => :finished_at
21
21
  #validates_absence_of :finished_at, :if => :position
22
22
  validates_presence_of :resolution, :if => :finished_at
23
- validates_uniqueness_of :description, :scope => :period_id
24
- validates_uniqueness_of :position, :scope => :period_id, :allow_nil => true
23
+ validates_uniqueness_of :description, :scope => :backlog_id, :if => :backlog_id
24
+ validates_uniqueness_of :description, :scope => :period_id, :if => :period_id
25
+ validates_uniqueness_of :position, :scope => :period_id, :if => :period_id, :allow_nil => true
26
+ validates_uniqueness_of :position, :scope => :parent_id, :if => :parent_id, :allow_nil => true
27
+ validates_uniqueness_of :position, :scope => :backlog_id, :if => Proc.new {|task| task.period_id.nil? && task.parent_id.nil?}, :allow_nil => true
25
28
 
26
29
  def validate
27
- unless (self.period_id || self.parent_id) && !(self.period_id && self.parent_id)
28
- errors.add :parent_id, "A task may have either period or parent task set, not both."
30
+ if self.parent_id && (self.period_id || self.backlog_id)
31
+ errors.add :parent_id, "A subtask may not have neither period nor backlog set."
29
32
  end
30
33
  if new_record? && self.period && self.period.passed?
31
34
  errors.add :period_id, "You may not add a task to a past period."
@@ -99,21 +102,21 @@ class Task < ActiveRecord::Base
99
102
 
100
103
  def open
101
104
  if finished_at
105
+ insert_at 1
102
106
  self.finished_at = nil
103
107
  self.resolution = nil
104
108
  estimate(initial_estimate)
105
- insert_at 1
106
109
  parent.open if parent
107
110
  end
108
111
  end
109
112
 
110
- def reopen(user)
113
+ def reopen
111
114
  if period.passed?
112
115
  flash[:notice] = "You cannot reopen a task in a period that is passed."
113
116
  else
114
- open(user)
117
+ open
115
118
  save!
116
- children.each {|child_task| child_task.reopen(user)}
119
+ children.each {|child_task| child_task.reopen}
117
120
  end
118
121
  end
119
122
 
@@ -137,24 +140,24 @@ class Task < ActiveRecord::Base
137
140
  self.finish(new_task.period.party == self.period.party ? Task::POSTPONED : Task::MOVED, true, current_user)
138
141
  end
139
142
 
140
- def finish(resolution, save_work, user)
143
+ def finish(resolution, save_work)
141
144
  unless finished_at || work_started?
142
145
  self.finished_at = Time.now
143
146
  self.resolution = resolution
147
+ remove_from_list
144
148
  self.position = nil
145
149
  save!
146
- remove_from_list
147
150
  estimate(0) if save_work
148
- parent.check_finished(self.finished_at, resolution, save_work, user) if parent
151
+ parent.check_finished(self.finished_at, resolution, save_work) if parent
149
152
  end
150
153
  end
151
154
 
152
- def check_finished(subtask_finsihed_at, resolution, save_work, user)
155
+ def check_finished(subtask_finsihed_at, resolution, save_work)
153
156
  return if self.finished_at
154
157
  children.each do |child_task|
155
158
  return if child_task.active?
156
159
  end
157
- finish(resolution, save_work, user)
160
+ finish(resolution, save_work)
158
161
  end
159
162
 
160
163
  def active?
@@ -263,14 +266,14 @@ class Task < ActiveRecord::Base
263
266
  total
264
267
  end
265
268
 
266
- def start_work(user)
269
+ def start_work
267
270
  return if work_started?
268
- open(user)
271
+ open
269
272
  new_work = works.new
270
273
  new_work.started_at = Time.previous_quarter
271
274
  if works.size > 0
272
- if user
273
- last_work = works.select {|work| work.user == user}.last
275
+ if current_user
276
+ last_work = works.select {|work| work.user == current_user}.last
274
277
  end
275
278
  unless last_work
276
279
  last_work = works.select {|work| work.user.nil?}.last
@@ -279,8 +282,16 @@ class Task < ActiveRecord::Base
279
282
  new_work.started_at = last_work.completed_at
280
283
  end
281
284
  end
282
- new_work.user = user
285
+ new_work.user = current_user
286
+ begin
283
287
  new_work.save!
288
+ rescue Exception => e
289
+ p e
290
+ p e.record
291
+ p e.record.task
292
+ p e.record.task.errors
293
+ p e.record.task.errors.full_messages
294
+ end
284
295
  end
285
296
 
286
297
  def works_with_children
@@ -288,7 +299,7 @@ class Task < ActiveRecord::Base
288
299
  end
289
300
 
290
301
  def abort(user)
291
- finish(Task::ABORTED, false, user)
302
+ finish(Task::ABORTED, false)
292
303
  end
293
304
 
294
305
  def work_started?
data/app/models/work.rb CHANGED
@@ -3,6 +3,7 @@ class Work < ActiveRecord::Base
3
3
  belongs_to :user
4
4
 
5
5
  validates_presence_of :task_id
6
+ validates_associated :task
6
7
  validates_presence_of :started_at
7
8
  validates_presence_of :user_id, :if => :validate_user?
8
9
 
@@ -34,14 +34,14 @@ function handlePageEvent(event) {
34
34
  <% if user? %>| <%=user.email%><% end %>
35
35
  </div>
36
36
  <div id="header">
37
+ <%= error_messages_for :backlog, :user, :group, :period, :task, :work, :estimate %>
38
+
37
39
  <div id="introtext">
38
40
  <h1><%=@application_title%></h1>
39
41
  <h3><%=@page_title ? @page_title : @application_description%></h3>
40
42
  </div>
41
43
  </div>
42
44
  <div id="content">
43
- <%= error_messages_for 'period', 'task' %>
44
-
45
45
  <%= yield %>
46
46
  </div>
47
47
  </div>
@@ -1,5 +1,3 @@
1
- <%= error_messages_for 'task' %>
2
-
3
1
  <!--[form:task]-->
4
2
  <p>
5
3
  <% if @task.backlog.nil? || @task.new_record? %>
@@ -12,6 +10,7 @@
12
10
  <% if @task.backlog %>
13
11
  <%=image_detour_to('clipboard.png', "#{l(:backlog)} #{@task.backlog.name}", {:controller => 'backlogs', :action => :edit, :id => @task.backlog}, {:class => 'image-submit', :style => 'vertical-align: bottom'}) %>
14
12
  <% end %>
13
+ <%=detour_to l(:new_backlog), :controller => 'backlogs', :action => :new %>
15
14
  </p>
16
15
 
17
16
 
@@ -8,7 +8,7 @@
8
8
  <% end %>
9
9
  </td>
10
10
  <td align="left" valign="top" width="1" nowrap="true">
11
- <%=detour_to @task.position.to_s, :controller => 'tasks', :action => :edit, :id => @task.id if @task.depth == 0 %>
11
+ <%=detour_to @task.position.to_s, :controller => 'tasks', :action => :edit, :id => @task.id if @task.position || @task.depth == 0 %>
12
12
  <%= ("&nbsp;" * @task.depth * 4) if @task.depth > 0 %>
13
13
  <%= l(@task.resolution.downcase) if @task.finished_at %>
14
14
  <%= "-" if @task.children.size > 0 %>
@@ -34,8 +34,8 @@
34
34
  <% end %>
35
35
  <% end -%>
36
36
  </td>
37
- <% if @task.track_done? %>
38
37
  <td align="<%=@task.loggable? ? 'center' : 'left'%>" nowrap="true" width="1">
38
+ <% if @task.track_done? %>
39
39
  <% if @task.loggable? || @task.finished_at -%>
40
40
  <% form_tag({:controller => 'works', :action => (@task.work_started? ? :edit : :create), :id => @task.started_work}) do %>
41
41
  <%= hidden_field('work', 'task_id', :value => @task.id)%>
@@ -48,8 +48,8 @@
48
48
  <%=t @task.total_done if @task.total_done != 0%>
49
49
  <% end -%>
50
50
  <% end -%>
51
- </td>
52
51
  <% end -%>
52
+ </td>
53
53
  <td nowrap="true" width="1">
54
54
  <% if active && @task.loggable? -%>
55
55
  <% form_tag({:controller => 'estimates', :action => 'create', :id => @task}) do %>
@@ -17,12 +17,12 @@ th.hours {text-align: right;}
17
17
  }
18
18
 
19
19
  #errorExplanation {
20
- width: 400px;
21
20
  border: 2px solid red;
22
21
  padding: 7px;
23
22
  padding-bottom: 12px;
24
23
  margin-bottom: 20px;
25
- background-color: #f0f0f0;
24
+ background: transparent;
25
+ float: right;
26
26
  }
27
27
 
28
28
  #errorExplanation h2 {
@@ -5,12 +5,26 @@ first:
5
5
  backlog_id: 1
6
6
  period_id: 1
7
7
  description: first task
8
- position: 1
8
+ position: 0
9
9
  another:
10
10
  id: 2
11
11
  created_at: 2007-06-12
12
12
  backlog_id: 1
13
13
  period_id: 2
14
14
  description: second task
15
+ position: 0
16
+ started:
17
+ id: 3
18
+ created_at: 2007-08-02 14:15:42
19
+ backlog_id: 1
20
+ period_id: 2
21
+ description: third task
22
+ position: 1
23
+ last:
24
+ id: 4
25
+ created_at: 2007-08-02 14:15:42
26
+ backlog_id: 1
27
+ period_id: 2
28
+ description: last task
15
29
  position: 2
16
30
 
@@ -4,7 +4,7 @@ first:
4
4
  task_id: 1
5
5
  started_at: 2007-06-12T13:35:00
6
6
  completed_at: 2007-06-12T14:35:00
7
- another:
7
+ started:
8
8
  id: 2
9
- task_id: 2
9
+ task_id: 3
10
10
  started_at: 2007-06-12T13:35:00
@@ -5,7 +5,7 @@ require 'tasks_controller'
5
5
  class TasksController; def rescue_action(e) raise e end; end
6
6
 
7
7
  class TasksControllerTest < Test::Unit::TestCase
8
- fixtures :users, :backlogs, :periods, :tasks, :works, :estimates
8
+ fixtures :parties, :users, :groups, :backlogs, :periods, :tasks, :works, :estimates
9
9
 
10
10
  def setup
11
11
  @controller = TasksController.new
@@ -65,6 +65,20 @@ class TasksControllerTest < Test::Unit::TestCase
65
65
  assert_equal num_tasks + 1, Task.count
66
66
  end
67
67
 
68
+ def test_create_without_period
69
+ num_tasks = Task.count
70
+
71
+ post :create, :task => {:description => 'an important task', :backlog_id => '2'}
72
+
73
+ task = assigns(:task)
74
+ assert_equal [], task.errors.full_messages
75
+
76
+ assert_response :redirect
77
+ assert_redirected_to :controller => 'backlogs', :action => 'show', :id => 2
78
+
79
+ assert_equal num_tasks + 1, Task.count
80
+ end
81
+
68
82
  def test_edit
69
83
  get :edit, :id => 1
70
84
 
@@ -86,4 +86,32 @@ class WorksControllerTest < Test::Unit::TestCase
86
86
  Work.find(1)
87
87
  }
88
88
  end
89
+
90
+ def test_update_with_finish
91
+ num_tasks = Task.count
92
+ num_open_tasks = Task.find_open.size
93
+ task = tasks(:started)
94
+ work = works(:started)
95
+
96
+ post :update, "commit"=>"Lagre", "action"=>"update", "id"=>work.id.to_s, "controller"=>"works", "estimate"=>{"todo"=>"0"}, "work"=>{"completed_at"=>"2007-08-02 14:15", "task_id"=> task.id.to_s, "user_id"=>"1000001", "started_at"=>"2007-08-02 14:00"}
97
+
98
+ assert_response :redirect
99
+ assert_redirected_to :controller => 'periods', :action => :show, :id => task.period, :task => nil
100
+
101
+ assert_equal num_tasks, Task.count
102
+ assert_equal num_open_tasks - 1, Task.find_open.size
103
+ assert_sequence
104
+ end
105
+
106
+
107
+ private
108
+
109
+ def assert_sequence
110
+ Period.find(:all).each do |p|
111
+ p.open_tasks.each_with_index do |t, i|
112
+ assert_equal i, t.position
113
+ end
114
+ end
115
+ end
116
+
89
117
  end
@@ -1,7 +1,7 @@
1
1
  require File.dirname(__FILE__) + '/../test_helper'
2
2
 
3
3
  class TaskTest < Test::Unit::TestCase
4
- fixtures :backlogs, :periods, :tasks, :estimates, :works
4
+ fixtures :parties, :users, :groups, :backlogs, :periods, :tasks, :estimates, :works
5
5
 
6
6
  # Replace this with your real tests.
7
7
  def test_truth
metadata CHANGED
@@ -3,15 +3,15 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: backlog
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.3.2
7
- date: 2007-08-02 00:00:00 +02:00
6
+ version: 0.3.3
7
+ date: 2007-08-03 00:00:00 +02:00
8
8
  summary: Application to aid collecting, processing, organizing, reviewing and doing tasks.
9
9
  require_paths:
10
10
  - lib
11
11
  email: ryand-ruby@zenspider.com
12
12
  homepage: http://www.zenspider.com/ZSS/Products/backlog/
13
13
  rubyforge_project: backlog
14
- description: == Backlog Welcome to Backlog! Backlog is a tool to help you collect and organize all your tasks, wether you are a single persion or a small or large group. === Installation * Install ruby * Install RubyGems * Install PostgreSQL * run <tt>sudo gem install backlog -y</tt> * run <tt>sudo backlog setup_linux</tt> * run <tt>sudo backlog start</tt> === Updates * run <tt>sudo backlog stop</tt> * run <tt>sudo gem update -y</tt> * run <tt>sudo backlog start</tt>
14
+ description: == Backlog Welcome to Backlog! Backlog is a tool to help you collect and organize all your tasks, wether you are a single persion or a small or large group. A timekeeping module is also included to track time spent on the different tasks. === Backlog is not meant to be * an issue tracker with customer communication. === Installation * Install ruby * Install RubyGems * Install PostgreSQL * run <tt>sudo gem install backlog -y</tt> * run <tt>sudo backlog setup_linux</tt> * run <tt>sudo backlog start</tt> === Updates * run <tt>sudo backlog stop</tt> * run <tt>sudo gem update -y</tt> * run <tt>sudo backlog start</tt>
15
15
  autorequire:
16
16
  default_executable:
17
17
  bindir: bin
@@ -105,7 +105,6 @@ files:
105
105
  - public/stylesheets/zpcal/themes/scroller-down.gif
106
106
  - public/stylesheets/zpcal/themes/scroller-up.gif
107
107
  - public/stylesheets/backlog.css
108
- - public/stylesheets/scaffold.css
109
108
  - public/stylesheets/user.css
110
109
  - public/robots.txt
111
110
  - public/404.html
@@ -1,74 +0,0 @@
1
- body { background-color: #fff; color: #333; }
2
-
3
- body, p, ol, ul, td {
4
- font-family: verdana, arial, helvetica, sans-serif;
5
- font-size: 13px;
6
- line-height: 18px;
7
- }
8
-
9
- pre {
10
- background-color: #eee;
11
- padding: 10px;
12
- font-size: 11px;
13
- }
14
-
15
- a { color: #000; }
16
- a:visited { color: #666; }
17
- a:hover { color: #fff; background-color:#000; }
18
-
19
- .fieldWithErrors {
20
- padding: 2px;
21
- background-color: red;
22
- display: table;
23
- }
24
-
25
- #errorExplanation {
26
- width: 400px;
27
- border: 2px solid red;
28
- padding: 7px;
29
- padding-bottom: 12px;
30
- margin-bottom: 20px;
31
- background-color: #f0f0f0;
32
- }
33
-
34
- #errorExplanation h2 {
35
- text-align: left;
36
- font-weight: bold;
37
- padding: 5px 5px 5px 15px;
38
- font-size: 12px;
39
- margin: -7px;
40
- background-color: #c00;
41
- color: #fff;
42
- }
43
-
44
- #errorExplanation p {
45
- color: #333;
46
- margin-bottom: 0;
47
- padding: 5px;
48
- }
49
-
50
- #errorExplanation ul li {
51
- font-size: 12px;
52
- list-style: square;
53
- }
54
-
55
- div.uploadStatus {
56
- margin: 5px;
57
- }
58
-
59
- div.progressBar {
60
- margin: 5px;
61
- }
62
-
63
- div.progressBar div.border {
64
- background-color: #fff;
65
- border: 1px solid grey;
66
- width: 100%;
67
- }
68
-
69
- div.progressBar div.background {
70
- background-color: #333;
71
- height: 18px;
72
- width: 0%;
73
- }
74
-