backlog 0.1.2 → 0.2.0

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 (42) hide show
  1. data/History.txt +9 -0
  2. data/Rakefile +1 -1
  3. data/app/controllers/application.rb +6 -5
  4. data/app/controllers/groups_controller.rb +2 -1
  5. data/app/controllers/periods_controller.rb +3 -4
  6. data/app/controllers/tasks_controller.rb +5 -2
  7. data/app/controllers/user_controller.rb +5 -5
  8. data/app/controllers/works_controller.rb +1 -2
  9. data/app/helpers/application_helper.rb +3 -2
  10. data/app/models/group.rb +6 -0
  11. data/app/models/party.rb +5 -0
  12. data/app/models/task.rb +18 -8
  13. data/app/models/user.rb +4 -0
  14. data/app/models/work.rb +4 -4
  15. data/app/views/backlogs/edit.rhtml +1 -2
  16. data/app/views/groups/edit.rhtml +17 -1
  17. data/app/views/groups/new.rhtml +3 -4
  18. data/app/views/layouts/mwrt002.rhtml +1 -1
  19. data/app/views/periods/_form.rhtml +4 -4
  20. data/app/views/periods/_show_active.rhtml +2 -2
  21. data/app/views/periods/_title.rhtml +3 -1
  22. data/app/views/periods/new.rhtml +2 -3
  23. data/app/views/tasks/_backlog_header.rhtml +4 -2
  24. data/app/views/tasks/_form.rhtml +4 -3
  25. data/app/views/tasks/_task.rhtml +19 -22
  26. data/app/views/tasks/edit.rhtml +2 -0
  27. data/app/views/tasks/list_started.rhtml +2 -1
  28. data/app/views/user/_edit.rhtml +3 -2
  29. data/app/views/user/_password.rhtml +4 -4
  30. data/app/views/user/edit.rhtml +29 -5
  31. data/app/views/works/_form.rhtml +5 -5
  32. data/app/views/works/weekly_work_sheet.rhtml +2 -2
  33. data/config/database.yml +1 -1
  34. data/lang/en.yaml +4 -0
  35. data/lang/no.yaml +5 -1
  36. data/lib/class_table_inheritance.rb +1 -1
  37. data/lib/user_system.rb +22 -12
  38. data/public/images/group.png +0 -0
  39. data/public/images/{person.png → user.png} +0 -0
  40. data/test/functional/tasks_controller_test.rb +19 -1
  41. data/test/functional/user_controller_test.rb +1 -1
  42. metadata +5 -3
@@ -1,3 +1,12 @@
1
+ == 0.2.0 2007-07-31
2
+
3
+ * Improved workflow
4
+
5
+ == 0.1.2 2007-07-29
6
+
7
+ * Improved gem generation
8
+ * Fixed bugs in user registration and initial setup
9
+
1
10
  == 0.1.1 2007-07-29
2
11
 
3
12
  * Improved gem generation
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ require 'tasks/rails'
11
11
 
12
12
  require 'hoe'
13
13
 
14
- Hoe.new("backlog", '0.1.2') do |p|
14
+ Hoe.new("backlog", '0.2.0') do |p|
15
15
  p.rubyforge_name = "backlog"
16
16
  p.description = p.paragraphs_of('README.txt', 0..-1).join("\n\n")
17
17
  p.remote_rdoc_dir = '' # Release to root
@@ -12,8 +12,8 @@ class ApplicationController < ActionController::Base
12
12
  layout :determine_layout
13
13
  helper :user
14
14
  before_filter :store_detour_from_params
15
- before_filter :populate_layout
16
15
  before_filter :authenticate_user
16
+ before_filter :populate_layout
17
17
 
18
18
  def self.in_place_edit_for(object, attribute, options = {})
19
19
  define_method("set_#{object}_#{attribute}") do
@@ -73,8 +73,8 @@ class ApplicationController < ActionController::Base
73
73
  end
74
74
 
75
75
  def store_detour_from_params
76
- if params[:return_controller] && params[:return_action]
77
- store_detour(:controller => params[:return_controller], :action => params[:return_action], :id => params[:return_id])
76
+ if params[:detour]
77
+ store_detour(params[:detour])
78
78
  end
79
79
  if params[:return_from_detour] && session[:detours]
80
80
  pop_detour
@@ -107,6 +107,7 @@ class ApplicationController < ActionController::Base
107
107
  {:key => 'Alt-N', :function => :new_task, :options => {:controller => 'tasks', :action => 'new', :period_id => (@period ? @period.id : (@backlog && @backlog.periods.first ? @backlog.periods.first.id : nil))}},
108
108
  {:key => 'Alt-Shift-N', :function => :new_period, :options => {:controller => 'periods', :action => 'new'}},
109
109
  {:key => 'Alt-Ctrl-N', :function => :new_backlog, :options => {:controller => 'backlogs', :action => 'new'}},
110
+ {:key => 'Alt-Ctrl-G', :function => :new_group, :options => {:controller => 'groups', :action => :new}},
110
111
  {:key => "Alt-#{l :up}", :function => :up},
111
112
  {:key => "Alt-#{l :down}", :function => :down},
112
113
  {:key => "Alt-Shift-#{l :left}", :function => :move_to_top},
@@ -122,7 +123,7 @@ class ApplicationController < ActionController::Base
122
123
  populate_shortcuts
123
124
 
124
125
  # TODO (uwe): This does not scale!
125
- periods = Period.find(:all).select {|period| period.active_or_future?(true)}
126
+ periods = Period.find(:all).select {|period| period.active_or_future?(true) && period.party.includes?(user)}
126
127
 
127
128
  @sidebars = periods.sort_by {|p| p.required_speed}.reverse.map do |period|
128
129
  content = '<ul>'
@@ -147,7 +148,7 @@ class ApplicationController < ActionController::Base
147
148
  started_tasks = Task.find_started(user)
148
149
  if not started_tasks.empty?
149
150
  links = started_tasks.map do |task|
150
- "<li><a href=\"#{url_for :controller => 'periods', :action => :show, :id => task.period, :task_id => task.id}\">#{task.description}</a></li>"
151
+ "<li><a href=\"#{url_for :controller => 'tasks', :action => :list_started, :id => task.id}\">#{task.description}</a></li>"
151
152
  end
152
153
  @sidebars.unshift({ :title => l(:started_tasks),
153
154
  :options => {:controller => 'tasks', :action => :list_started},
@@ -20,7 +20,7 @@ class GroupsController < ApplicationController
20
20
  @group = Group.new(params[:group])
21
21
  if @group.save
22
22
  flash[:notice] = 'Group was successfully created.'
23
- redirect_to :action => 'list'
23
+ back_or_redirect_to :action => 'list'
24
24
  else
25
25
  render :action => 'new'
26
26
  end
@@ -30,6 +30,7 @@ class GroupsController < ApplicationController
30
30
  @group = Group.find(params[:id])
31
31
  @users = User.find(:all)
32
32
  @members = @group.users.to_s
33
+ @groups = Group.find(:all, :order => 'name')
33
34
  end
34
35
 
35
36
  def update
@@ -37,8 +37,8 @@ class PeriodsController < ApplicationController
37
37
 
38
38
  def new
39
39
  @period = Period.new
40
- if params[:party_id]
41
- @period.party_id = params[:party_id]
40
+ if params[:period] && params[:period][:party_id]
41
+ @period.party_id = params[:period][:party_id]
42
42
  previous = @period.party.periods.last
43
43
  if previous
44
44
  @period.start_on = previous.end_on + 1
@@ -46,9 +46,8 @@ class PeriodsController < ApplicationController
46
46
  else
47
47
  @period.start_on = Date.today
48
48
  end
49
- else
50
- @parties = Party.find(:all)
51
49
  end
50
+ @parties = Party.find(:all)
52
51
  end
53
52
 
54
53
  def create
@@ -7,10 +7,12 @@ class TasksController < ApplicationController
7
7
 
8
8
  def list_started
9
9
  @tasks = Task.find_started(user)
10
+ @selected_task = Task.find_by_id(params[:id])
10
11
  back_or_redirect_to :controller => nil, :action => nil if @tasks.empty?
11
12
  end
12
13
 
13
14
  def new
15
+ redirect_to params if request.post?
14
16
  @task = Task.new params[:task]
15
17
  @task.backlog_id ||= @task.period && @task.period.most_frequent_backlog
16
18
  @backlogs = Backlog.find(:all, :order => 'name')
@@ -36,6 +38,7 @@ class TasksController < ApplicationController
36
38
  def edit
37
39
  @task = Task.find(params[:id])
38
40
  @periods = Period.find_active_or_future
41
+ @backlogs = Backlog.find(:all, :order => 'name')
39
42
  end
40
43
 
41
44
  def update
@@ -126,7 +129,7 @@ class TasksController < ApplicationController
126
129
  back_or_redirect_to :controller => 'periods', :action => :show_nolayout, :id => next_task.period, :task_id => next_task.id
127
130
  end
128
131
  else
129
- detour_to :controller => 'periods', :action => :new, :party_id => task.period.party_id, :layout => with_layout && determine_layout
132
+ detour_to :controller => 'periods', :action => :new, :period => {:party_id => task.period.party_id}, :layout => with_layout && determine_layout
130
133
  end
131
134
  else
132
135
  redirect_to :controller => 'periods', :action => :show, :id => task.period, :task_id => task.id, :layout => with_layout && determine_layout
@@ -167,7 +170,7 @@ class TasksController < ApplicationController
167
170
  def end_work
168
171
  @task = Task.find(params[:id])
169
172
  next_quarter = Time.next_quarter
170
- if started_work = @task.started_work(user)
173
+ if started_work = @task.started_work
171
174
  redirect_to({
172
175
  :controller => 'works',
173
176
  :action => :edit,
@@ -12,8 +12,7 @@ class UserController < ApplicationController
12
12
  @user = User.new(params['user'])
13
13
  user = User.authenticate(params['user']['login'], params['user']['password'])
14
14
  if user
15
- @current_user = user
16
- session[:user_id] = user.id
15
+ self.current_user = user
17
16
  flash['notice'] = 'Login succeeded'
18
17
  back_or_redirect_to :controller => 'backlogs', :action => :index
19
18
  else
@@ -46,7 +45,7 @@ class UserController < ApplicationController
46
45
 
47
46
  def logout
48
47
  session[:user_id] = nil
49
- @current_user = nil
48
+ self.current_user = nil
50
49
  cookies.delete :autologin
51
50
  redirect_to :action => 'login'
52
51
  end
@@ -130,7 +129,7 @@ class UserController < ApplicationController
130
129
  end
131
130
 
132
131
  def delete
133
- @user = @current_user || User.find_by_id( session[:user_id] )
132
+ @user = current_user || User.find_by_id( session[:user_id] )
134
133
  begin
135
134
  @user.update_attribute( :deleted, true )
136
135
  logout
@@ -166,7 +165,8 @@ class UserController < ApplicationController
166
165
 
167
166
  # Generate a template user for certain actions on get
168
167
  def generate_filled_in
169
- @user = @current_user || User.find_by_id( session[:user_id] )
168
+ @user = User.find_by_id(params[:id]) || current_user || User.find_by_id(session[:user_id])
169
+ @groups = Group.find(:all, :order => 'name')
170
170
  case request.method
171
171
  when :get
172
172
  render
@@ -57,8 +57,6 @@ class WorksController < ApplicationController
57
57
  def update
58
58
  @work = Work.find(params[:id])
59
59
 
60
- @work.task.estimates.new(params[:estimate]).save! if params[:estimate]
61
-
62
60
  convert_start_time_param
63
61
  convert_hours_param
64
62
  if @work.update_attributes(params[:work])
@@ -67,6 +65,7 @@ class WorksController < ApplicationController
67
65
  else
68
66
  render :action => 'edit'
69
67
  end
68
+ @work.task.estimates.new(params[:estimate]).save! if params[:estimate]
70
69
  end
71
70
 
72
71
  def destroy
@@ -11,8 +11,9 @@ module ApplicationHelper
11
11
  :onclick => "form.action='#{url_for(options)}'"
12
12
  end
13
13
 
14
- def detour_to(title, options)
15
- link_to title, options.update({:return_controller => @controller.controller_name, :return_action => @controller.action_name, :return_id => params[:id]})
14
+ def detour_to(title, options, html_options = nil)
15
+ #link_to title, options.update({:detour => {:controller => @controller.controller_name, :action => @controller.action_name, :id => params[:id]}}), html_options
16
+ link_to title, options.update({:detour => params.reject {|k, v| [:detour, :return_from_detour].include? k.to_sym}}), html_options
16
17
  end
17
18
 
18
19
  def image_detour_to(image_source, title, image_options, options )
@@ -8,4 +8,10 @@ class Group < Party
8
8
 
9
9
  validates_presence_of :name
10
10
  validates_length_of :name, :allow_nil => false, :maximum => 255
11
+ validates_uniqueness_of :name
12
+
13
+ def includes?(user)
14
+ return users.include?(user)
15
+ end
16
+
11
17
  end
@@ -1,3 +1,8 @@
1
1
  class Party < ActiveRecord::Base
2
2
  has_many :periods, :order => :position, :dependent => :destroy
3
+
4
+ def to_sym
5
+ self.class.name.downcase.to_sym
6
+ end
7
+
3
8
  end
@@ -1,4 +1,6 @@
1
1
  class Task < ActiveRecord::Base
2
+ include UserSystem
3
+
2
4
  COMPLETED = 'COMPLETED'
3
5
  POSTPONED = 'POSTPONED'
4
6
  MOVED = 'MOVED'
@@ -132,7 +134,7 @@ class Task < ActiveRecord::Base
132
134
  end
133
135
 
134
136
  def finish(resolution, save_work, user)
135
- unless finished_at || work_started?(user)
137
+ unless finished_at || work_started?
136
138
  remove_from_list
137
139
  self.finished_at = Time.now
138
140
  self.resolution = resolution
@@ -152,7 +154,7 @@ class Task < ActiveRecord::Base
152
154
  end
153
155
 
154
156
  def active?
155
- finished_at.nil? || active_children?
157
+ finished_at.nil? || work_started? || active_children?
156
158
  end
157
159
 
158
160
  def active_children?
@@ -201,10 +203,18 @@ class Task < ActiveRecord::Base
201
203
  root_task.backlog.enable_subtasks?
202
204
  end
203
205
 
206
+ def enable_users?
207
+ root_task.backlog.enable_users?
208
+ end
209
+
204
210
  def enable_customer?
205
211
  root_task.backlog.enable_customer?
206
212
  end
207
213
 
214
+ def enable_invoicing?
215
+ root_task.backlog.enable_invoicing?
216
+ end
217
+
208
218
  alias_method :old_period, :period
209
219
  def period
210
220
  old_period || root_task.old_period
@@ -250,7 +260,7 @@ class Task < ActiveRecord::Base
250
260
  end
251
261
 
252
262
  def start_work(user)
253
- return if work_started?(user)
263
+ return if work_started?
254
264
  open(user)
255
265
  new_work = works.new
256
266
  new_work.started_at = Time.previous_quarter
@@ -277,14 +287,14 @@ class Task < ActiveRecord::Base
277
287
  finish(Task::ABORTED, false, user)
278
288
  end
279
289
 
280
- def work_started?(user)
281
- !started_work(user).nil?
290
+ def work_started?
291
+ !started_work.nil?
282
292
  end
283
293
 
284
- def started_work(user)
294
+ def started_work
285
295
  started_works = works.select {|work| work.completed_at.nil?}
286
- if user
287
- started_by_user = started_works.select {|work| work.user == user}.last
296
+ if current_user
297
+ started_by_user = started_works.select {|work| work.user == current_user}.last
288
298
  return started_by_user if started_by_user
289
299
  end
290
300
  started_works.select {|work| work.user.nil?}.last
@@ -93,6 +93,10 @@ class User < Party
93
93
  def name
94
94
  [first_name, last_name].compact.join(' ')
95
95
  end
96
+
97
+ def includes?(user)
98
+ return user == self
99
+ end
96
100
 
97
101
  protected
98
102
 
@@ -2,12 +2,12 @@ class Work < ActiveRecord::Base
2
2
  belongs_to :task
3
3
  belongs_to :user
4
4
 
5
- validates_associated :task
5
+ validates_presence_of :task_id
6
6
  validates_presence_of :started_at
7
- validates_associated :user_id, :if => :validate_user?
7
+ validates_presence_of :user_id, :if => :validate_user?
8
8
 
9
9
  def validate_user?
10
- task.backlog.enable_users
10
+ task.enable_users?
11
11
  end
12
12
 
13
13
  def track_times?
@@ -27,7 +27,7 @@ class Work < ActiveRecord::Base
27
27
  works = find(:all, :conditions => "completed_at BETWEEN '#{first.to_time.iso8601}' AND '#{last.to_time.iso8601}'", :order => 'completed_at')
28
28
  length = 0
29
29
  works_per_day = (0..6).map do |day|
30
- 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
+ works_for_day = works.select {|work| work.completed_at.to_date == (first + day) && (!work.task.enable_users? || (user && work.user_id == user.id)) }
31
31
  length = [length, works_for_day.length].max
32
32
  works_for_day
33
33
  end
@@ -4,7 +4,6 @@
4
4
  <% form_tag :action => 'update', :id => @backlog do %>
5
5
  <%= render :partial => 'form' %>
6
6
  <%= submit_tag l(:save) %>
7
+ <%= back_or_link_to l(:back), :action => 'show', :id => @backlog %>
7
8
  <% end %>
8
-
9
- <%= back_or_link_to l(:back), :action => 'show', :id => @backlog %>
10
9
  </div>
@@ -16,7 +16,7 @@
16
16
  <table>
17
17
  <% for @user in @users %>
18
18
  <tr>
19
- <td><%=h @user.name%></td>
19
+ <td><%=link_to h(@user.name), :controller => 'user', :action => :edit, :id => @user %></td>
20
20
  <td>
21
21
  <% form_for :group, @group, :url => {:action => :set_member, :id => @group, :user_id => @user.id} do %>
22
22
  <%=check_box_tag :value, true, @group.users.include?(@user), :onchange => "form.submit()" %></td>
@@ -29,3 +29,19 @@
29
29
 
30
30
  </div>
31
31
 
32
+ <div id="rfeature">
33
+ <div class="btitle">
34
+ <h4><%=l :groups %></h4>
35
+ </div>
36
+
37
+ <table>
38
+ <% for @group in @groups %>
39
+ <tr>
40
+ <td>
41
+ <%=link_to @group.name, :action => :edit, :id => @group%>
42
+ </tr>
43
+ <% end %>
44
+ </table>
45
+
46
+ </div>
47
+
@@ -1,8 +1,7 @@
1
- <h1>New group</h1>
1
+ <% @page_title = l :new_group %>
2
2
 
3
3
  <% form_tag :action => 'create' do %>
4
4
  <%= render :partial => 'form' %>
5
- <%= submit_tag "Create" %>
5
+ <%= submit_tag l(:save) %>
6
+ <%= back_or_link_to l(:back), :action => 'list' %>
6
7
  <% end %>
7
-
8
- <%= link_to 'Back', :action => 'list' %>
@@ -54,7 +54,7 @@ function handlePageEvent(event) {
54
54
  <table>
55
55
  <% @shortcuts.each_with_index do |shortcut, index| %>
56
56
  <% if shortcut[:options] %>
57
- <tr><td valign="top"><%= shortcut[:key]%></td><td><%= link_to l(shortcut[:function]), shortcut[:options], :id => shortcut[:function], :tabindex => index+100 %></td></tr>
57
+ <tr><td valign="top"><%= shortcut[:key]%></td><td><%=detour_to l(shortcut[:function]), shortcut[:options], :id => shortcut[:function], :tabindex => index+100 %></td></tr>
58
58
  <% else %>
59
59
  <tr><td valign="top"><%= shortcut[:key]%></td><td><%=l shortcut[:function] %></td></tr>
60
60
  <% end %>
@@ -1,12 +1,12 @@
1
1
  <%= error_messages_for 'period' %>
2
2
 
3
3
  <!--[form:period]-->
4
- <% if @period.party %>
4
+ <% if @period.new_record? %>
5
+ <p><label for="period_party_id"><%=l :group%>/<%=l :user%></label><br/>
6
+ <%= select 'period', 'party_id', [['', '']] + @parties.map{|party| [party.name, party.id]}, {}, :onchange => "form.action = '#{url_for :action => :new}'; form.submit();" %></p>
7
+ <% else %>
5
8
  <p><label for="period_party_id"><%=l @period.party.class.name.downcase.to_s%></label>:
6
9
  <%= hidden_field 'period', 'party_id' %><%=detour_to h(@period.party.name), :controller => @period.party.type.name.downcase.pluralize, :action => :edit, :id => @period.party%></p>
7
- <% else %>
8
- <p><label for="period_party_id"><%=l :group%>/<%=l :user%></label><br/>
9
- <%= select 'period', 'party_id', @parties.map{|party| [party.name, party.id]} %></p>
10
10
  <% end %>
11
11
 
12
12
  <%= hidden_field 'period', 'position' %>
@@ -31,7 +31,7 @@ function handleEvent(field, event, id) {
31
31
  //-->
32
32
  </script>
33
33
 
34
- <% if @tasks and not @tasks.empty? %>
34
+ <% if @tasks and not @tasks.empty?%>
35
35
  <table class="input">
36
36
  <% current_backlog = nil %>
37
37
  <% for task in @tasks %>
@@ -40,7 +40,7 @@ function handleEvent(field, event, id) {
40
40
  <%=render :partial => '/tasks/backlog_header', :locals => { :backlog => task.backlog } %>
41
41
  <% current_backlog = task.backlog %>
42
42
  <% end %>
43
- <%=render :partial => '/tasks/task', :locals => { :task => task, :i => i, :active => true } %>
43
+ <%=render :partial => '/tasks/task', :locals => { :task => task, :i => i, :active => true, :highlight => task == @selected_task } %>
44
44
  <% i += 1 %>
45
45
  <% end %>
46
46
  </table>
@@ -2,7 +2,9 @@
2
2
  <%= render :partial => '/works/buttons'%>
3
3
  <%=if @period.lower_item then link_to(image_tag(url_for("arrow_right.png"), :alt => "#{l :next} #{l :period}", :title => "#{l :next} #{l :period}", :class => 'image-submit'), :controller => 'periods', :action => :show, :id => @period.lower_item) end%>
4
4
  <%=link_to(image_tag(url_for("period.png"), :alt => l(:period), :title => l(:period), :class => 'image-submit'), :controller => 'periods', :action => :edit, :id => @period) %>
5
- <%=detour_to(image_tag(url_for("person.png"), :alt => l(:group), :title => l(:group), :class => 'image-submit'), :controller => 'groups', :action => :edit, :id => @period.party) %>
5
+
6
+ <%=detour_to(image_tag(url_for(@period.party.to_sym.to_s + ".png"), :alt => l(@period.party.to_sym), :title => l(@period.party.to_sym), :class => 'image-submit'), :controller => @period.party.to_sym.to_s, :action => :edit, :id => @period.party) %>
7
+
6
8
  <%=if @period.higher_item then link_to(image_tag(url_for("arrow_left.png"), :alt => "#{l :previous} #{l :period}", :title => "#{l :previous} #{l :period}", :class => 'image-submit'), :controller => 'periods', :action => :show, :id => @period.higher_item) end%>
7
9
  <%=unless @period.passed? then link_to(image_tag(url_for("add.png"), :alt => l(:add_task), :title => l(:add_task), :class => 'image-submit'), :controller => 'tasks', :action => 'new', :task => {:period_id => (@period ? @period.id : (@backlog && @backlog.periods.first ? @backlog.periods.first.id : nil))} ) end %>
8
10
  <h4><%=h @period.name %> (<%=@period.start_on%> - <%=@period.end_on%>)</h4>
@@ -3,8 +3,7 @@
3
3
 
4
4
  <% form_tag :action => 'create' do %>
5
5
  <%= render :partial => 'form' %>
6
- <%= submit_tag "Create" %>
6
+ <%= submit_tag l(:save) %>
7
+ <%= back_or_link_to l(:back), :action => 'list' %>
7
8
  <% end %>
8
-
9
- <%= back_or_link_to l(:back), :action => 'list' %>
10
9
  </div>
@@ -1,14 +1,16 @@
1
1
  <% @backlog = backlog %>
2
+
2
3
  <tr valign="top">
3
4
  <td>
4
5
  <%= image_detour_to('add.png', l(:new_task), nil, :controller => 'tasks', :action => :new, :task => {:backlog_id => @backlog.id, :period_id => @period.id})%>
5
6
  </td>
6
- <td colspan="7" valign="top">
7
+ <td colspan="4" valign="top">
7
8
  <h5>
8
9
  <%=h backlog.name %>
9
10
  <%=image_detour_to("clipboard.png", l(:backlog), nil, :controller => 'backlogs', :action => :edit, :id => @backlog) %>
10
11
  </h5>
11
12
  </td>
13
+ <td width="*"/>
12
14
  </tr>
13
15
  <tr>
14
16
  <th/>
@@ -18,5 +20,5 @@
18
20
  <% if @period.track_work? -%>
19
21
  <th><%=l :done %></th>
20
22
  <% end %>
21
- <th><% if @backlog.track_todo? %><%=l :todo %><% end %></th>
23
+ <th width="*"><% l :todo if @backlog.track_todo? %></th>
22
24
  </tr>
@@ -16,10 +16,11 @@
16
16
 
17
17
 
18
18
  <p><label for="task_period_id"><%=l :period%></label><br/>
19
- <%= select 'task', 'period_id', [['', '']] + @periods.map{|p| [p.name, p.id]} %>
19
+ <%= select 'task', 'period_id', [['', '']] + @periods.map{|p| [p.name, p.id]}, {}, :onchange => "form.action = '#{url_for}'; form.submit();" %>
20
20
  <% if @task.period %>
21
- <%=image_detour_to('person.png', 'Group', nil, :controller => 'groups', :action => :edit, :id => @task.period.party) %>
21
+ <%=image_detour_to(@task.period.party.to_sym.to_s + '.png', "#{l(@task.period.party.to_sym)} #{@task.period.party.name}", nil, :controller => @task.period.party.to_s, :action => :edit, :id => @task.period.party) %>
22
22
  <% end %>
23
+ <%=detour_to l(:new_period), :controller => 'periods', :action => :new %>
23
24
  </p>
24
25
 
25
26
 
@@ -44,5 +45,5 @@
44
45
 
45
46
 
46
47
  <script type="text/JavaScript">
47
- document.forms[0].elements[1].focus();
48
+ document.forms[0].elements[<%=@task.backlog.nil? ? 0 : @task.period.nil? ? 1 : 2%>].focus();
48
49
  </script>
@@ -1,19 +1,16 @@
1
1
  <% @task = task %>
2
- <tr valign="top">
3
- <td>
2
+ <tr valign="top" <%= 'style="background-color: yellow"' if highlight %>>
3
+ <td width="1">
4
4
  <% if @task.enable_subtasks? && @task.period.active_or_future? && active %>
5
5
  <% form_tag({:controller => 'tasks', :action => :specify, :id => @task}) do %>
6
6
  <%= image_button_to('add.png', l(:specify), :controller => 'tasks', :action => :specify, :id => @task.id)%>
7
7
  <% end %>
8
8
  <% end %>
9
9
  </td>
10
- <td align="left" valign="top">
11
- <% form_tag({:controller => 'tasks', :action => 'update', :id => @task}) do %>
12
- <%= submit_tag('checkmark', :value => l(:save), :style => 'display: none')%>
13
- <%= ("&nbsp;" * @task.depth * 4) if @task.depth > 0 %>
14
- <%= l @task.resolution.downcase if @task.finished_at %>
15
- <%= "-" if @task.children.size > 0 %>
16
- <% end %>
10
+ <td align="left" valign="top" width="1" nowrap="true">
11
+ <%= ("&nbsp;" * @task.depth * 4) if @task.depth > 0 %>
12
+ <%= l(@task.resolution.downcase) if @task.finished_at %>
13
+ <%= "-" if @task.children.size > 0 %>
17
14
  </td>
18
15
  <td id="<%=@task.id%>" <%if active && @task.period.active_or_future?%>class="tasks" style=cursor:move;"<%end%>>
19
16
  <% if @task.active? -%>
@@ -22,12 +19,12 @@
22
19
  <%= @task.description -%>
23
20
  <% end -%>
24
21
  </td>
25
- <td align="right" nowrap="true">
26
- <% if @task.loggable? -%>
27
- <% form_tag({:controller => 'works', :action => 'update', :id => @task.started_work(user)}) do %>
22
+ <td align="right" nowrap="true" width="1">
23
+ <% if active && @task.loggable? -%>
24
+ <% form_tag({:controller => 'works', :action => 'update', :id => @task.started_work}) do %>
28
25
  <%= submit_tag('checkmark', :value => l(:save), :style => 'display: none')%>
29
- <% if @task.work_started?(user) -%>
30
- <%= text_field 'work', 'started_at_time', :tabindex => i+1, :value => @task.started_work(user).started_at.strftime('%H:%M'),
26
+ <% if @task.work_started? -%>
27
+ <%= text_field 'work', 'started_at_time', :tabindex => i+1, :value => @task.started_work.started_at.strftime('%H:%M'),
31
28
  :class => :task_time, :maxlength => 5, :onkeypress => "handleEvent(this, event, #{@task.id})" %>
32
29
  <%= image_button_to('ernes_stop.png', l(:end_work), :controller => 'tasks', :action => :end_work, :id => @task.id) %>
33
30
  <% elsif @task.track_times? && @task.period.active? %>
@@ -37,12 +34,12 @@
37
34
  <% end -%>
38
35
  </td>
39
36
  <% if @task.track_done? %>
40
- <td align="<%=@task.loggable? ? 'center' : 'left'%>" nowrap="true">
37
+ <td align="<%=@task.loggable? ? 'center' : 'left'%>" nowrap="true" width="1">
41
38
  <% if @task.loggable? || @task.finished_at -%>
42
- <% form_tag({:controller => 'works', :action => (@task.work_started?(user) ? :edit : :create), :id => @task.started_work(user)}) do %>
39
+ <% form_tag({:controller => 'works', :action => (@task.work_started? ? :edit : :create), :id => @task.started_work}) do %>
43
40
  <%= hidden_field('work', 'task_id', :value => @task.id)%>
44
41
  <%= submit_tag('checkmark', :value => l(:save), :style => 'display: none')%>
45
- <% unless @task.track_times? || @task.work_started?(user) || @task.finished_at -%>
42
+ <% unless @task.track_times? || @task.work_started? || @task.finished_at -%>
46
43
  <%= text_field 'work', 'hours', :tabindex => i+1, :id => "#{@task.id}_done",
47
44
  :class => :task_hours, :maxlength => 4, :onkeypress => "handleEvent(this, event, #{@task.id})",
48
45
  :ondblclick => "form.elements[1].style.display = 'inline';this.style.display = 'none'" -%>
@@ -52,8 +49,8 @@
52
49
  <% end -%>
53
50
  </td>
54
51
  <% end -%>
55
- <td nowrap="true">
56
- <% if @task.loggable? -%>
52
+ <td nowrap="true" width="1">
53
+ <% if active && @task.loggable? -%>
57
54
  <% form_tag({:controller => 'estimates', :action => 'create', :id => @task}) do %>
58
55
  <%= submit_tag('checkmark', :value => l(:save), :style => 'display: none')%>
59
56
  <% if @task.track_todo? %>
@@ -63,17 +60,17 @@
63
60
  <%= @task.todo %>
64
61
  <% end %>
65
62
  <% end -%>
66
- <% if (not @task.track_times?) && !@task.work_started?(user) && @task.period.active? %>
63
+ <% if (not @task.track_times?) && !@task.work_started? && @task.period.active? %>
67
64
  <%= image_button_to('checkmark.png', l(:complete), :controller => 'tasks', :action => :finish, :id => @task)%>
68
65
  <% end -%>
69
66
  <% end -%>
70
67
  <% end -%>
71
68
  </td>
72
- <td align="right" nowrap="true" width="*">
69
+ <td align="right" nowrap="true" width="1">
73
70
  <% form_tag({:controller => 'tasks', :action => 'update', :id => @task}) do %>
74
71
  <% if @task.active? %>
75
72
  <% if @task.loggable? %>
76
- <% unless @task.work_started?(user) %>
73
+ <% unless @task.work_started? %>
77
74
  <%= image_button_to('arrow_right.png', l(:move_to_next_period), :controller => 'tasks', :action => :move_to_next_period, :id => @task)%>
78
75
  <%= image_button_to('ernes_stop.png', l(:abort), :controller => 'tasks', :action => :abort, :id => @task)%>
79
76
  <% end %>
@@ -1,6 +1,8 @@
1
1
  <div id="spotlight">
2
2
  <h1>Editing task</h1>
3
3
 
4
+ <%=h @task.inspect%>
5
+
4
6
  <% form_tag :action => 'update', :id => @task do %>
5
7
  <%= render :partial => 'form' %>
6
8
  <%= submit_tag l(:save) %>
@@ -38,6 +38,7 @@ function handleEvent(field, event, id) {
38
38
  <% if @tasks %>
39
39
  <table class="input">
40
40
  <tr>
41
+ <th/>
41
42
  <th align="center">#</th>
42
43
  <th><%=l :task %></th>
43
44
  <th><%=l :start %></th>
@@ -46,7 +47,7 @@ function handleEvent(field, event, id) {
46
47
  </tr>
47
48
  <% i = 0 %>
48
49
  <% for task in @tasks %>
49
- <%=render :partial => 'task', :locals => { :task => task, :i => i, :active => true } %>
50
+ <%=render :partial => 'task', :locals => { :task => task, :i => i, :active => true, :highlight => task == @selected_task } %>
50
51
  <% i += 1 %>
51
52
  <% end %>
52
53
  </table>
@@ -21,8 +21,9 @@
21
21
  </tr>
22
22
  <% if submit %>
23
23
  <tr>
24
- <td>
25
- <%= submit_tag user.new_record? ? 'signup' : 'change_settings', :class => 'two_columns' %>
24
+ <td colspan="2">
25
+ <%= submit_tag user.new_record? ? 'signup' : l(:save), :class => 'two_columns' %>
26
+ <%= back_or_link_to l(:back), :action => 'list' %>
26
27
  </td>
27
28
  </tr>
28
29
  <% end %>
@@ -4,16 +4,16 @@
4
4
  <table>
5
5
  <tr class="two_columns">
6
6
  <td class="prompt"><label>Password:</label></td>
7
- <td class="value"><%= password_field 'user', 'password', :size => 30 %></td>
7
+ <td class="value"><%= password_field 'user', 'password', :size => 16 %></td>
8
8
  </tr>
9
9
  <tr class="two_columns">
10
10
  <td class="prompt"><label>Password confirmation:</label></td>
11
- <td class="value"><%= password_field 'user', 'password_confirmation', :size => 30 %></td>
11
+ <td class="value"><%= password_field 'user', 'password_confirmation', :size => 16 %></td>
12
12
  </tr>
13
13
  <% if submit %>
14
14
  <tr>
15
- <td>
16
- <%= submit_tag 'change_password' %>
15
+ <td colspan="2">
16
+ <%= submit_tag l(:change_password) %>
17
17
  </td>
18
18
  </tr>
19
19
  <% end %>
@@ -1,10 +1,16 @@
1
- <div title="<%= title_helper %>" class="form">
2
- <%= head_helper 'Edit User', :error => true %>
1
+ <div id="spotlight" title="<%= title_helper %>" class="form">
2
+ <% @page_title = "#{l :editing} #{l :user}" %>
3
3
 
4
4
  <%= start_form_tag_helper %>
5
5
  <%= render_partial 'edit', :user => @user, :submit => true %>
6
6
  </form>
7
- </br>
7
+ </div>
8
+
9
+ <div id="rfeature">
10
+ <div class="btitle">
11
+ <h4><%=l :password %></h4>
12
+ </div>
13
+
8
14
  <%= start_form_tag_helper %>
9
15
  <%= render_partial 'password', :submit => true %>
10
16
  </form>
@@ -12,8 +18,26 @@
12
18
  <%= start_form_tag_helper %>
13
19
  <div class="user_delete">
14
20
  <%= hidden_field 'user', 'form', :value => 'delete' %>
15
- <%= submit_tag 'Delete' %>
21
+ <%= submit_tag l(:delete) %>
16
22
  </div>
17
23
  </form>
18
24
  </div>
19
- </div>
25
+ </div>
26
+
27
+ <div id="lfeature">
28
+ <div class="btitle">
29
+ <h4><%=l :groups %></h4>
30
+ </div>
31
+
32
+ <table>
33
+ <% for @group in @groups %>
34
+ <tr>
35
+ <td><%=link_to h(@group.name), :controller => 'groups', :action => :edit, :id => @group %></td>
36
+ <td>
37
+ <% form_for :group, @group, :url => {:controller => 'groups', :action => :set_member, :id => @group, :user_id => @user.id} do %>
38
+ <%=check_box_tag :value, true, @group.users.include?(@user), :onchange => "form.submit()" %></td>
39
+ <% end %>
40
+ </tr>
41
+ <% end %>
42
+ </table>
43
+ </div>
@@ -10,7 +10,7 @@
10
10
  <%= select 'work', 'task_id', @tasks.map{|task| [task.description, task.id]} %></p>
11
11
  <% end %>
12
12
 
13
- <% if @work.task.nil? || @work.task.backlog.track_times?%>
13
+ <% if @work.task.nil? || @work.task.track_times?%>
14
14
  <p><label for="work_started_at"><%=l :started_at%></label><br/>
15
15
  <%= text_field 'work', 'started_at', :size => 16, :value => @work.started_at ? @work.started_at.strftime('%Y-%m-%d %H:%M') : nil %>
16
16
  <button id="trigger1">...</button>
@@ -50,23 +50,23 @@
50
50
  </p>
51
51
  <% end %>
52
52
 
53
- <% if @work.task.nil? || @work.task.backlog.enable_users %>
53
+ <% if @work.task.nil? || @work.task.enable_users? %>
54
54
  <p><label for="work_user_id"><%=l :user%></label><br/>
55
55
  <%= select 'work', 'user_id', @users.map{|user| [user.login, user.id]} %></p>
56
56
  <% end %>
57
57
 
58
- <% if @work.task.nil? || @work.task.backlog.track_done?%>
58
+ <% if @work.task.nil? || @work.task.track_done?%>
59
59
  <p style="float: left;"><label for="work_hours"><%=l :hours%></label><br/>
60
60
  <%= text_field 'work', 'hours_time', :class => :task_hours, :value => t(@work.hours) %></p>
61
61
  <% end %>
62
62
 
63
- <% if @work.task.nil? || @work.task.backlog.enable_invoicing? %>
63
+ <% if @work.task.nil? || @work.task.enable_invoicing? %>
64
64
  <p style="float: left;"><br/><%= check_box 'work', 'invoice' %><label for="work_invoice"><%=l :invoice%>?</label></p>
65
65
  <% end %>
66
66
 
67
67
  <br clear="all"/>
68
68
 
69
- <% if @work.task.nil? || @work.task.backlog.track_todo?%>
69
+ <% if @work.task.nil? || @work.task.track_todo?%>
70
70
  <p><label for="estimate_todo"><%=l :todo%></label><br/>
71
71
  <%= text_field 'estimate', 'todo', :class => :task_hours %>
72
72
  <%= image_tag('checkmark.png', :onclick => "document.forms[0].elements['estimate_todo'].value='0'", :style => 'vertical-align: bottom; height: 24px; float: none')%>
@@ -1,8 +1,8 @@
1
1
  <% @page_title = l(:weekly_work_sheet) + (@period ? " for #{@period}" : '') + (user? ? " for #{user.login}" : '')%>
2
2
 
3
3
  <div id="spotlight">
4
- <% track_times = @rows.find {|r| r.find {|w| w && w.task.backlog.track_times?}} %>
5
- <% invoicing = @rows.find {|r| r.find {|w| w && w.task.backlog.enable_invoicing?}} %>
4
+ <% track_times = @rows.find {|r| r.find {|w| w && w.task.track_times?}} %>
5
+ <% invoicing = @rows.find {|r| r.find {|w| w && w.task.enable_invoicing?}} %>
6
6
  <% columns = 2 + (track_times ? 2 : 0) + (invoicing ? 1 : 0) %>
7
7
 
8
8
  <h1>Work for week <%=@week%><%=user? ? " for #{user.login}" : ''%></h1>
@@ -1,7 +1,7 @@
1
1
  development:
2
2
  adapter: postgresql
3
3
  database: backlog_development
4
- username: #{`whoami`}
4
+ username: uwe
5
5
  host: localhost
6
6
 
7
7
  # Warning: The database defined as 'test' will be erased and
@@ -8,6 +8,7 @@ back: Back
8
8
  backlog: Backlog
9
9
  backlog_description: Task list with ordering and status tracking
10
10
  burn_down_chart: Burn Down Chart
11
+ change_password: Change Password
11
12
  complete: Complete
12
13
  completed: Completed
13
14
  completed_at: Ended at
@@ -27,6 +28,7 @@ end_work: Stop
27
28
  estimate: Estimate
28
29
  friday: Friday
29
30
  group: Group
31
+ groups: Groups
30
32
  home: Home
31
33
  hours: Hours
32
34
  invoice: Invoice
@@ -43,11 +45,13 @@ move_to_next_period: Move task to next period
43
45
  move_to_top: Move task to top of list
44
46
  name: Name
45
47
  new_backlog: Start new backlog
48
+ new_group: Start new group
46
49
  new_period: Add new period
47
50
  new_task: Add new task
48
51
  new_work: Add new work record
49
52
  next: Next
50
53
  no_pending_tasks: There are no pending tasks in this period.
54
+ password: Password
51
55
  period: Period
52
56
  position: Position
53
57
  postponed: Postponed
@@ -8,6 +8,7 @@ back: Tilbake
8
8
  backlog: Oppgaveliste
9
9
  backlog_description: Oppgaveliste med sortering og statussporing
10
10
  burn_down_chart: Fremdriftsgraf
11
+ change_password: Bytt Passord
11
12
  complete: Fullfør
12
13
  completed: Fullført
13
14
  completed_at: Stop tid
@@ -27,6 +28,7 @@ end_work: Stopp
27
28
  estimate: Estimat
28
29
  friday: Fredag
29
30
  group: Gruppe
31
+ groups: Grupper
30
32
  home: Hjem
31
33
  hours: Timer
32
34
  invoice: Fakturerbart
@@ -39,15 +41,17 @@ main_backlog: Hovedliste
39
41
  members: Medlemmer
40
42
  monday: Mandag
41
43
  move_to_bottom: Flytt oppgaven til slutten av listen
42
- move_to_next_period: Flytt oppgaven til nexte periode
44
+ move_to_next_period: Flytt oppgaven til neste periode
43
45
  move_to_top: Flytt oppgaven til toppen av listen
44
46
  name: Navn
45
47
  new_backlog: Start ny oppgaveliste
48
+ new_group: Start ny gruppe
46
49
  new_period: Start ny periode
47
50
  new_task: Legg til ny oppgave
48
51
  new_work: Registrer arbeid
49
52
  next: Neste
50
53
  no_pending_tasks: Det er ingen ventende oppgaver i denne perioden.
54
+ password: Passord
51
55
  period: Periode
52
56
  position: Posisjon
53
57
  postponed: Utsatt
@@ -115,7 +115,7 @@ class ActiveRecord::Base
115
115
  end
116
116
  end
117
117
 
118
- delegate :foreign_keys, {:to => #{proxy_class_name}}
118
+ delegate :foreign_keys, :validates_uniqueness_of, {:to => #{proxy_class_name}}
119
119
  end
120
120
  EOV
121
121
 
@@ -7,7 +7,12 @@ module UserSystem
7
7
  # before_filter :authenticate_user
8
8
  #
9
9
  def authenticate_user
10
- return true if authenticated_user?
10
+ if authenticated_user = authenticated_user?
11
+ self.current_user = authenticated_user
12
+ return true
13
+ end
14
+ session[:user_id] = nil
15
+ Thread.current[:user] = nil
11
16
  store_detour_from_params
12
17
  access_denied
13
18
  return false
@@ -33,9 +38,9 @@ module UserSystem
33
38
 
34
39
  def authenticated_user?
35
40
  if session[:user_id]
36
- @current_user = User.find_by_id(session[:user_id])
37
- return true if @current_user
38
- session[:user_id]
41
+ current_user = User.find_by_id(session[:user_id])
42
+ return current_user if current_user
43
+ session[:user_id] = nil
39
44
  end
40
45
 
41
46
  if cookie = cookies[:autologin]
@@ -47,11 +52,8 @@ module UserSystem
47
52
  else
48
53
  raise "Unknown cookie class: #{cookie.class}"
49
54
  end
50
- @current_user = User.authenticate(cookie_value, '')
51
- if @current_user
52
- session[:user_id] = @current_user.id
53
- return true
54
- end
55
+ cookie_user = User.authenticate(cookie_value, '')
56
+ return cookie_user if cookie_user
55
57
  end
56
58
 
57
59
  # If not, is the user being authenticated by a token (created by signup/forgot password actions)?
@@ -59,12 +61,20 @@ module UserSystem
59
61
  id = params['user']['id']
60
62
  key = params['key']
61
63
  if id and key
62
- @current_user = User.authenticate_by_token(id, key)
63
- session[:user_id] = @current_user ? @current_user.id : nil
64
- return true if not @current_user.nil?
64
+ return current_user if current_user = User.authenticate_by_token(id, key)
65
65
  end
66
66
 
67
67
  # Everything failed
68
68
  return false
69
69
  end
70
+
71
+ def current_user
72
+ Thread.current[:user]
73
+ end
74
+
75
+ def current_user= user
76
+ session[:user_id] = user && user.id
77
+ Thread.current[:user] = user
78
+ end
79
+
70
80
  end
Binary file
File without changes
@@ -24,6 +24,24 @@ class TasksControllerTest < Test::Unit::TestCase
24
24
  assert_redirected_to :controller => 'backlogs'
25
25
  end
26
26
 
27
+ def test_list_started
28
+ get :list_started, :id => '1'
29
+ assert_response :success
30
+ assert_template 'list_started'
31
+
32
+ assert_not_nil assigns(:tasks)
33
+ assert_not_nil assigns(:selected_task)
34
+ end
35
+
36
+ def test_list_started_no_selected_task
37
+ get :list_started
38
+ assert_response :success
39
+ assert_template 'list_started'
40
+
41
+ assert_not_nil assigns(:tasks)
42
+ assert_nil assigns(:selected_task)
43
+ end
44
+
27
45
  def test_new
28
46
  get :new
29
47
 
@@ -100,7 +118,7 @@ class TasksControllerTest < Test::Unit::TestCase
100
118
  assert_response :redirect
101
119
  assert_redirected_to :controller => 'periods',
102
120
  :action => :new,
103
- :party_id => 1
121
+ :period => {:party_id => 1}
104
122
 
105
123
  after = Task.find(2)
106
124
  assert_equal 2, before.period_id
@@ -241,7 +241,7 @@ class UserControllerTest < Test::Unit::TestCase
241
241
 
242
242
  def assert_logged_in( user )
243
243
  assert_equal user.id, @request.session[:user_id]
244
- assert_equal user, assigns(:current_user)
244
+ assert_equal user, Thread.current[:user]
245
245
  end
246
246
 
247
247
  def assert_not_logged_in
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: backlog
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.2
7
- date: 2007-07-29 00:00:00 +02:00
6
+ version: 0.2.0
7
+ date: 2007-07-31 00:00:00 +02:00
8
8
  summary: The author was too lazy to write a summary
9
9
  require_paths:
10
10
  - lib
@@ -44,13 +44,13 @@ files:
44
44
  - public/images/arrow_right.svg
45
45
  - public/images/arrow_down.png
46
46
  - public/images/eraser_org.png
47
- - public/images/person.png
48
47
  - public/images/period.png
49
48
  - public/images/arrow_right.png
50
49
  - public/images/construction_hammer_jon__01.svg
51
50
  - public/images/arrow_down.svg
52
51
  - public/images/checkmark_org.png
53
52
  - public/images/pagebak.jpg
53
+ - public/images/group.png
54
54
  - public/images/tabella_architetto_franc_01.svg
55
55
  - public/images/header.jpg
56
56
  - public/images/rails.png
@@ -62,6 +62,7 @@ files:
62
62
  - public/images/blank.jpg
63
63
  - public/images/period_org.png
64
64
  - public/images/arrow07_4.png
65
+ - public/images/user.png
65
66
  - public/images/arrow07_2.png
66
67
  - public/images/appunti_architetto_franc_01.svg
67
68
  - public/images/eraser.png
@@ -225,6 +226,7 @@ files:
225
226
  - config/environments/datek_production.rb
226
227
  - LICENSE_LOCALIZATION
227
228
  - README.txt
229
+ - doc
228
230
  - Manifest.txt
229
231
  - vendor
230
232
  - vendor/plugins