backlog 0.1.2 → 0.2.0

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