##// END OF EJS Templates
Issue subject is not updated when you select another issue on time entry form (#24041)....
Jean-Philippe Lang -
r15569:2544fe6e15d4
parent child
Show More
@@ -0,0 +1,1
1 $('#time_entry_issue').html('<%= escape_javascript link_to_issue(@time_entry.issue) if @time_entry.issue.try(:visible?) %>');
@@ -1,49 +1,47
1 <%= error_messages_for 'time_entry' %>
1 <%= error_messages_for 'time_entry' %>
2 <%= back_url_hidden_field_tag %>
2 <%= back_url_hidden_field_tag %>
3
3
4 <div class="box tabular">
4 <div class="box tabular">
5 <% if @time_entry.new_record? %>
5 <% if @time_entry.new_record? %>
6 <% if params[:project_id] %>
6 <% if params[:project_id] %>
7 <%= hidden_field_tag 'project_id', params[:project_id] %>
7 <%= hidden_field_tag 'project_id', params[:project_id] %>
8 <% elsif params[:issue_id] %>
8 <% elsif params[:issue_id] %>
9 <%= hidden_field_tag 'issue_id', params[:issue_id] %>
9 <%= hidden_field_tag 'issue_id', params[:issue_id] %>
10 <% else %>
10 <% else %>
11 <p><%= f.select :project_id, project_tree_options_for_select(Project.allowed_to(:log_time).to_a, :selected => @time_entry.project, :include_blank => true), :required => true %></p>
11 <p><%= f.select :project_id, project_tree_options_for_select(Project.allowed_to(:log_time).to_a, :selected => @time_entry.project, :include_blank => true), :required => true %></p>
12 <% end %>
12 <% end %>
13 <% end %>
13 <% end %>
14 <p>
14 <p>
15 <%= f.text_field :issue_id, :size => 6 %>
15 <%= f.text_field :issue_id, :size => 6 %>
16 <% if @time_entry.issue.try(:visible?) %>
16 <span id="time_entry_issue">
17 <span id="time_entry_issue"><%= "#{@time_entry.issue.tracker.name} ##{@time_entry.issue.id}: #{@time_entry.issue.subject}" %></span>
17 <%= link_to_issue(@time_entry.issue) if @time_entry.issue.try(:visible?) %>
18 <% end %>
18 </span>
19 </p>
19 </p>
20 <p><%= f.date_field :spent_on, :size => 10, :required => true %><%= calendar_for('time_entry_spent_on') %></p>
20 <p><%= f.date_field :spent_on, :size => 10, :required => true %><%= calendar_for('time_entry_spent_on') %></p>
21 <p><%= f.text_field :hours, :size => 6, :required => true %></p>
21 <p><%= f.text_field :hours, :size => 6, :required => true %></p>
22 <p><%= f.text_field :comments, :size => 100, :maxlength => 1024 %></p>
22 <p><%= f.text_field :comments, :size => 100, :maxlength => 1024 %></p>
23 <p><%= f.select :activity_id, activity_collection_for_select_options(@time_entry), :required => true %></p>
23 <p><%= f.select :activity_id, activity_collection_for_select_options(@time_entry), :required => true %></p>
24 <% @time_entry.custom_field_values.each do |value| %>
24 <% @time_entry.custom_field_values.each do |value| %>
25 <p><%= custom_field_tag_with_label :time_entry, value %></p>
25 <p><%= custom_field_tag_with_label :time_entry, value %></p>
26 <% end %>
26 <% end %>
27 <%= call_hook(:view_timelog_edit_form_bottom, { :time_entry => @time_entry, :form => f }) %>
27 <%= call_hook(:view_timelog_edit_form_bottom, { :time_entry => @time_entry, :form => f }) %>
28 </div>
28 </div>
29
29
30 <%= javascript_tag do %>
30 <%= javascript_tag do %>
31 <% if @time_entry.new_record? %>
32 $(document).ready(function(){
31 $(document).ready(function(){
33 $('#time_entry_project_id, #time_entry_issue_id').change(function(){
32 $('#time_entry_project_id, #time_entry_issue_id').change(function(){
34 $.ajax({
33 $.ajax({
35 url: '<%= escape_javascript new_time_entry_path(:format => 'js') %>',
34 url: '<%= escape_javascript(@time_entry.new_record? ? new_time_entry_path(:format => 'js') : edit_time_entry_path(:format => 'js')) %>',
36 type: 'post',
35 type: 'post',
37 data: $('#new_time_entry').serialize()
36 data: $(this).closest('form').serialize()
38 });
37 });
39 });
38 });
40 });
39 });
41 <% end %>
42
40
43 observeAutocompleteField('time_entry_issue_id', '<%= escape_javascript auto_complete_issues_path(:project_id => @project, :scope => (@project ? nil : 'all'))%>', {
41 observeAutocompleteField('time_entry_issue_id', '<%= escape_javascript auto_complete_issues_path(:project_id => @project, :scope => (@project ? nil : 'all'))%>', {
44 select: function(event, ui) {
42 select: function(event, ui) {
45 $('#time_entry_issue').text(ui.item.label);
43 $('#time_entry_issue').text('');
46 $('#time_entry_issue_id').blur();
44 $('#time_entry_issue_id').val(ui.item.value).change();
47 }
45 }
48 });
46 });
49 <% end %>
47 <% end %>
@@ -1,1 +1,2
1 $('#time_entry_activity_id').html('<%= escape_javascript options_for_select(activity_collection_for_select_options(@time_entry), @time_entry.activity_id) %>');
1 $('#time_entry_activity_id').html('<%= escape_javascript options_for_select(activity_collection_for_select_options(@time_entry), @time_entry.activity_id) %>');
2 $('#time_entry_issue').html('<%= escape_javascript link_to_issue(@time_entry.issue) if @time_entry.issue.try(:visible?) %>');
@@ -1,384 +1,388
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 Rails.application.routes.draw do
18 Rails.application.routes.draw do
19 root :to => 'welcome#index', :as => 'home'
19 root :to => 'welcome#index', :as => 'home'
20
20
21 match 'login', :to => 'account#login', :as => 'signin', :via => [:get, :post]
21 match 'login', :to => 'account#login', :as => 'signin', :via => [:get, :post]
22 match 'logout', :to => 'account#logout', :as => 'signout', :via => [:get, :post]
22 match 'logout', :to => 'account#logout', :as => 'signout', :via => [:get, :post]
23 match 'account/register', :to => 'account#register', :via => [:get, :post], :as => 'register'
23 match 'account/register', :to => 'account#register', :via => [:get, :post], :as => 'register'
24 match 'account/lost_password', :to => 'account#lost_password', :via => [:get, :post], :as => 'lost_password'
24 match 'account/lost_password', :to => 'account#lost_password', :via => [:get, :post], :as => 'lost_password'
25 match 'account/activate', :to => 'account#activate', :via => :get
25 match 'account/activate', :to => 'account#activate', :via => :get
26 get 'account/activation_email', :to => 'account#activation_email', :as => 'activation_email'
26 get 'account/activation_email', :to => 'account#activation_email', :as => 'activation_email'
27
27
28 match '/news/preview', :controller => 'previews', :action => 'news', :as => 'preview_news', :via => [:get, :post, :put, :patch]
28 match '/news/preview', :controller => 'previews', :action => 'news', :as => 'preview_news', :via => [:get, :post, :put, :patch]
29 match '/issues/preview/new/:project_id', :to => 'previews#issue', :as => 'preview_new_issue', :via => [:get, :post, :put, :patch]
29 match '/issues/preview/new/:project_id', :to => 'previews#issue', :as => 'preview_new_issue', :via => [:get, :post, :put, :patch]
30 match '/issues/preview/edit/:id', :to => 'previews#issue', :as => 'preview_edit_issue', :via => [:get, :post, :put, :patch]
30 match '/issues/preview/edit/:id', :to => 'previews#issue', :as => 'preview_edit_issue', :via => [:get, :post, :put, :patch]
31 match '/issues/preview', :to => 'previews#issue', :as => 'preview_issue', :via => [:get, :post, :put, :patch]
31 match '/issues/preview', :to => 'previews#issue', :as => 'preview_issue', :via => [:get, :post, :put, :patch]
32
32
33 match 'projects/:id/wiki', :to => 'wikis#edit', :via => :post
33 match 'projects/:id/wiki', :to => 'wikis#edit', :via => :post
34 match 'projects/:id/wiki/destroy', :to => 'wikis#destroy', :via => [:get, :post]
34 match 'projects/:id/wiki/destroy', :to => 'wikis#destroy', :via => [:get, :post]
35
35
36 match 'boards/:board_id/topics/new', :to => 'messages#new', :via => [:get, :post], :as => 'new_board_message'
36 match 'boards/:board_id/topics/new', :to => 'messages#new', :via => [:get, :post], :as => 'new_board_message'
37 get 'boards/:board_id/topics/:id', :to => 'messages#show', :as => 'board_message'
37 get 'boards/:board_id/topics/:id', :to => 'messages#show', :as => 'board_message'
38 match 'boards/:board_id/topics/quote/:id', :to => 'messages#quote', :via => [:get, :post]
38 match 'boards/:board_id/topics/quote/:id', :to => 'messages#quote', :via => [:get, :post]
39 get 'boards/:board_id/topics/:id/edit', :to => 'messages#edit'
39 get 'boards/:board_id/topics/:id/edit', :to => 'messages#edit'
40
40
41 post 'boards/:board_id/topics/preview', :to => 'messages#preview', :as => 'preview_board_message'
41 post 'boards/:board_id/topics/preview', :to => 'messages#preview', :as => 'preview_board_message'
42 post 'boards/:board_id/topics/:id/replies', :to => 'messages#reply'
42 post 'boards/:board_id/topics/:id/replies', :to => 'messages#reply'
43 post 'boards/:board_id/topics/:id/edit', :to => 'messages#edit'
43 post 'boards/:board_id/topics/:id/edit', :to => 'messages#edit'
44 post 'boards/:board_id/topics/:id/destroy', :to => 'messages#destroy'
44 post 'boards/:board_id/topics/:id/destroy', :to => 'messages#destroy'
45
45
46 # Misc issue routes. TODO: move into resources
46 # Misc issue routes. TODO: move into resources
47 match '/issues/auto_complete', :to => 'auto_completes#issues', :via => :get, :as => 'auto_complete_issues'
47 match '/issues/auto_complete', :to => 'auto_completes#issues', :via => :get, :as => 'auto_complete_issues'
48 match '/issues/context_menu', :to => 'context_menus#issues', :as => 'issues_context_menu', :via => [:get, :post]
48 match '/issues/context_menu', :to => 'context_menus#issues', :as => 'issues_context_menu', :via => [:get, :post]
49 match '/issues/changes', :to => 'journals#index', :as => 'issue_changes', :via => :get
49 match '/issues/changes', :to => 'journals#index', :as => 'issue_changes', :via => :get
50 match '/issues/:id/quoted', :to => 'journals#new', :id => /\d+/, :via => :post, :as => 'quoted_issue'
50 match '/issues/:id/quoted', :to => 'journals#new', :id => /\d+/, :via => :post, :as => 'quoted_issue'
51
51
52 resources :journals, :only => [:edit, :update] do
52 resources :journals, :only => [:edit, :update] do
53 member do
53 member do
54 get 'diff'
54 get 'diff'
55 end
55 end
56 end
56 end
57
57
58 get '/projects/:project_id/issues/gantt', :to => 'gantts#show', :as => 'project_gantt'
58 get '/projects/:project_id/issues/gantt', :to => 'gantts#show', :as => 'project_gantt'
59 get '/issues/gantt', :to => 'gantts#show'
59 get '/issues/gantt', :to => 'gantts#show'
60
60
61 get '/projects/:project_id/issues/calendar', :to => 'calendars#show', :as => 'project_calendar'
61 get '/projects/:project_id/issues/calendar', :to => 'calendars#show', :as => 'project_calendar'
62 get '/issues/calendar', :to => 'calendars#show'
62 get '/issues/calendar', :to => 'calendars#show'
63
63
64 get 'projects/:id/issues/report', :to => 'reports#issue_report', :as => 'project_issues_report'
64 get 'projects/:id/issues/report', :to => 'reports#issue_report', :as => 'project_issues_report'
65 get 'projects/:id/issues/report/:detail', :to => 'reports#issue_report_details', :as => 'project_issues_report_details'
65 get 'projects/:id/issues/report/:detail', :to => 'reports#issue_report_details', :as => 'project_issues_report_details'
66
66
67 get '/issues/imports/new', :to => 'imports#new', :as => 'new_issues_import'
67 get '/issues/imports/new', :to => 'imports#new', :as => 'new_issues_import'
68 post '/imports', :to => 'imports#create', :as => 'imports'
68 post '/imports', :to => 'imports#create', :as => 'imports'
69 get '/imports/:id', :to => 'imports#show', :as => 'import'
69 get '/imports/:id', :to => 'imports#show', :as => 'import'
70 match '/imports/:id/settings', :to => 'imports#settings', :via => [:get, :post], :as => 'import_settings'
70 match '/imports/:id/settings', :to => 'imports#settings', :via => [:get, :post], :as => 'import_settings'
71 match '/imports/:id/mapping', :to => 'imports#mapping', :via => [:get, :post], :as => 'import_mapping'
71 match '/imports/:id/mapping', :to => 'imports#mapping', :via => [:get, :post], :as => 'import_mapping'
72 match '/imports/:id/run', :to => 'imports#run', :via => [:get, :post], :as => 'import_run'
72 match '/imports/:id/run', :to => 'imports#run', :via => [:get, :post], :as => 'import_run'
73
73
74 match 'my/account', :controller => 'my', :action => 'account', :via => [:get, :post]
74 match 'my/account', :controller => 'my', :action => 'account', :via => [:get, :post]
75 match 'my/account/destroy', :controller => 'my', :action => 'destroy', :via => [:get, :post]
75 match 'my/account/destroy', :controller => 'my', :action => 'destroy', :via => [:get, :post]
76 match 'my/page', :controller => 'my', :action => 'page', :via => :get
76 match 'my/page', :controller => 'my', :action => 'page', :via => :get
77 post 'my/page', :to => 'my#update_page'
77 post 'my/page', :to => 'my#update_page'
78 match 'my', :controller => 'my', :action => 'index', :via => :get # Redirects to my/page
78 match 'my', :controller => 'my', :action => 'index', :via => :get # Redirects to my/page
79 get 'my/api_key', :to => 'my#show_api_key', :as => 'my_api_key'
79 get 'my/api_key', :to => 'my#show_api_key', :as => 'my_api_key'
80 post 'my/api_key', :to => 'my#reset_api_key'
80 post 'my/api_key', :to => 'my#reset_api_key'
81 post 'my/rss_key', :to => 'my#reset_rss_key', :as => 'my_rss_key'
81 post 'my/rss_key', :to => 'my#reset_rss_key', :as => 'my_rss_key'
82 match 'my/password', :controller => 'my', :action => 'password', :via => [:get, :post]
82 match 'my/password', :controller => 'my', :action => 'password', :via => [:get, :post]
83 match 'my/page_layout', :controller => 'my', :action => 'page_layout', :via => :get
83 match 'my/page_layout', :controller => 'my', :action => 'page_layout', :via => :get
84 match 'my/add_block', :controller => 'my', :action => 'add_block', :via => :post
84 match 'my/add_block', :controller => 'my', :action => 'add_block', :via => :post
85 match 'my/remove_block', :controller => 'my', :action => 'remove_block', :via => :post
85 match 'my/remove_block', :controller => 'my', :action => 'remove_block', :via => :post
86 match 'my/order_blocks', :controller => 'my', :action => 'order_blocks', :via => :post
86 match 'my/order_blocks', :controller => 'my', :action => 'order_blocks', :via => :post
87
87
88 resources :users do
88 resources :users do
89 resources :memberships, :controller => 'principal_memberships'
89 resources :memberships, :controller => 'principal_memberships'
90 resources :email_addresses, :only => [:index, :create, :update, :destroy]
90 resources :email_addresses, :only => [:index, :create, :update, :destroy]
91 end
91 end
92
92
93 post 'watchers/watch', :to => 'watchers#watch', :as => 'watch'
93 post 'watchers/watch', :to => 'watchers#watch', :as => 'watch'
94 delete 'watchers/watch', :to => 'watchers#unwatch'
94 delete 'watchers/watch', :to => 'watchers#unwatch'
95 get 'watchers/new', :to => 'watchers#new', :as => 'new_watchers'
95 get 'watchers/new', :to => 'watchers#new', :as => 'new_watchers'
96 post 'watchers', :to => 'watchers#create'
96 post 'watchers', :to => 'watchers#create'
97 post 'watchers/append', :to => 'watchers#append'
97 post 'watchers/append', :to => 'watchers#append'
98 delete 'watchers', :to => 'watchers#destroy'
98 delete 'watchers', :to => 'watchers#destroy'
99 get 'watchers/autocomplete_for_user', :to => 'watchers#autocomplete_for_user'
99 get 'watchers/autocomplete_for_user', :to => 'watchers#autocomplete_for_user'
100 # Specific routes for issue watchers API
100 # Specific routes for issue watchers API
101 post 'issues/:object_id/watchers', :to => 'watchers#create', :object_type => 'issue'
101 post 'issues/:object_id/watchers', :to => 'watchers#create', :object_type => 'issue'
102 delete 'issues/:object_id/watchers/:user_id' => 'watchers#destroy', :object_type => 'issue'
102 delete 'issues/:object_id/watchers/:user_id' => 'watchers#destroy', :object_type => 'issue'
103
103
104 resources :projects do
104 resources :projects do
105 member do
105 member do
106 get 'settings(/:tab)', :action => 'settings', :as => 'settings'
106 get 'settings(/:tab)', :action => 'settings', :as => 'settings'
107 post 'modules'
107 post 'modules'
108 post 'archive'
108 post 'archive'
109 post 'unarchive'
109 post 'unarchive'
110 post 'close'
110 post 'close'
111 post 'reopen'
111 post 'reopen'
112 match 'copy', :via => [:get, :post]
112 match 'copy', :via => [:get, :post]
113 end
113 end
114
114
115 shallow do
115 shallow do
116 resources :memberships, :controller => 'members', :only => [:index, :show, :new, :create, :update, :destroy] do
116 resources :memberships, :controller => 'members', :only => [:index, :show, :new, :create, :update, :destroy] do
117 collection do
117 collection do
118 get 'autocomplete'
118 get 'autocomplete'
119 end
119 end
120 end
120 end
121 end
121 end
122
122
123 resource :enumerations, :controller => 'project_enumerations', :only => [:update, :destroy]
123 resource :enumerations, :controller => 'project_enumerations', :only => [:update, :destroy]
124
124
125 get 'issues/:copy_from/copy', :to => 'issues#new', :as => 'copy_issue'
125 get 'issues/:copy_from/copy', :to => 'issues#new', :as => 'copy_issue'
126 resources :issues, :only => [:index, :new, :create]
126 resources :issues, :only => [:index, :new, :create]
127 # Used when updating the form of a new issue
127 # Used when updating the form of a new issue
128 post 'issues/new', :to => 'issues#new'
128 post 'issues/new', :to => 'issues#new'
129
129
130 resources :files, :only => [:index, :new, :create]
130 resources :files, :only => [:index, :new, :create]
131
131
132 resources :versions, :except => [:index, :show, :edit, :update, :destroy] do
132 resources :versions, :except => [:index, :show, :edit, :update, :destroy] do
133 collection do
133 collection do
134 put 'close_completed'
134 put 'close_completed'
135 end
135 end
136 end
136 end
137 get 'versions.:format', :to => 'versions#index'
137 get 'versions.:format', :to => 'versions#index'
138 get 'roadmap', :to => 'versions#index', :format => false
138 get 'roadmap', :to => 'versions#index', :format => false
139 get 'versions', :to => 'versions#index'
139 get 'versions', :to => 'versions#index'
140
140
141 resources :news, :except => [:show, :edit, :update, :destroy]
141 resources :news, :except => [:show, :edit, :update, :destroy]
142 resources :time_entries, :controller => 'timelog', :except => [:show, :edit, :update, :destroy] do
142 resources :time_entries, :controller => 'timelog', :except => [:show, :edit, :update, :destroy] do
143 get 'report', :on => :collection
143 get 'report', :on => :collection
144 end
144 end
145 resources :queries, :only => [:new, :create]
145 resources :queries, :only => [:new, :create]
146 shallow do
146 shallow do
147 resources :issue_categories
147 resources :issue_categories
148 end
148 end
149 resources :documents, :except => [:show, :edit, :update, :destroy]
149 resources :documents, :except => [:show, :edit, :update, :destroy]
150 resources :boards
150 resources :boards
151 shallow do
151 shallow do
152 resources :repositories, :except => [:index, :show] do
152 resources :repositories, :except => [:index, :show] do
153 member do
153 member do
154 match 'committers', :via => [:get, :post]
154 match 'committers', :via => [:get, :post]
155 end
155 end
156 end
156 end
157 end
157 end
158
158
159 match 'wiki/index', :controller => 'wiki', :action => 'index', :via => :get
159 match 'wiki/index', :controller => 'wiki', :action => 'index', :via => :get
160 resources :wiki, :except => [:index, :create], :as => 'wiki_page' do
160 resources :wiki, :except => [:index, :create], :as => 'wiki_page' do
161 member do
161 member do
162 get 'rename'
162 get 'rename'
163 post 'rename'
163 post 'rename'
164 get 'history'
164 get 'history'
165 get 'diff'
165 get 'diff'
166 match 'preview', :via => [:post, :put, :patch]
166 match 'preview', :via => [:post, :put, :patch]
167 post 'protect'
167 post 'protect'
168 post 'add_attachment'
168 post 'add_attachment'
169 end
169 end
170 collection do
170 collection do
171 get 'export'
171 get 'export'
172 get 'date_index'
172 get 'date_index'
173 post 'new'
173 post 'new'
174 end
174 end
175 end
175 end
176 match 'wiki', :controller => 'wiki', :action => 'show', :via => :get
176 match 'wiki', :controller => 'wiki', :action => 'show', :via => :get
177 get 'wiki/:id/:version', :to => 'wiki#show', :constraints => {:version => /\d+/}
177 get 'wiki/:id/:version', :to => 'wiki#show', :constraints => {:version => /\d+/}
178 delete 'wiki/:id/:version', :to => 'wiki#destroy_version'
178 delete 'wiki/:id/:version', :to => 'wiki#destroy_version'
179 get 'wiki/:id/:version/annotate', :to => 'wiki#annotate'
179 get 'wiki/:id/:version/annotate', :to => 'wiki#annotate'
180 get 'wiki/:id/:version/diff', :to => 'wiki#diff'
180 get 'wiki/:id/:version/diff', :to => 'wiki#diff'
181 end
181 end
182
182
183 resources :issues do
183 resources :issues do
184 member do
184 member do
185 # Used when updating the form of an existing issue
185 # Used when updating the form of an existing issue
186 patch 'edit', :to => 'issues#edit'
186 patch 'edit', :to => 'issues#edit'
187 end
187 end
188 collection do
188 collection do
189 match 'bulk_edit', :via => [:get, :post]
189 match 'bulk_edit', :via => [:get, :post]
190 post 'bulk_update'
190 post 'bulk_update'
191 end
191 end
192 resources :time_entries, :controller => 'timelog', :only => [:new, :create]
192 resources :time_entries, :controller => 'timelog', :only => [:new, :create]
193 shallow do
193 shallow do
194 resources :relations, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
194 resources :relations, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
195 end
195 end
196 end
196 end
197 # Used when updating the form of a new issue outside a project
197 # Used when updating the form of a new issue outside a project
198 post '/issues/new', :to => 'issues#new'
198 post '/issues/new', :to => 'issues#new'
199 match '/issues', :controller => 'issues', :action => 'destroy', :via => :delete
199 match '/issues', :controller => 'issues', :action => 'destroy', :via => :delete
200
200
201 resources :queries, :except => [:show]
201 resources :queries, :except => [:show]
202
202
203 resources :news, :only => [:index, :show, :edit, :update, :destroy]
203 resources :news, :only => [:index, :show, :edit, :update, :destroy]
204 match '/news/:id/comments', :to => 'comments#create', :via => :post
204 match '/news/:id/comments', :to => 'comments#create', :via => :post
205 match '/news/:id/comments/:comment_id', :to => 'comments#destroy', :via => :delete
205 match '/news/:id/comments/:comment_id', :to => 'comments#destroy', :via => :delete
206
206
207 resources :versions, :only => [:show, :edit, :update, :destroy] do
207 resources :versions, :only => [:show, :edit, :update, :destroy] do
208 post 'status_by', :on => :member
208 post 'status_by', :on => :member
209 end
209 end
210
210
211 resources :documents, :only => [:show, :edit, :update, :destroy] do
211 resources :documents, :only => [:show, :edit, :update, :destroy] do
212 post 'add_attachment', :on => :member
212 post 'add_attachment', :on => :member
213 end
213 end
214
214
215 match '/time_entries/context_menu', :to => 'context_menus#time_entries', :as => :time_entries_context_menu, :via => [:get, :post]
215 match '/time_entries/context_menu', :to => 'context_menus#time_entries', :as => :time_entries_context_menu, :via => [:get, :post]
216
216
217 resources :time_entries, :controller => 'timelog', :except => :destroy do
217 resources :time_entries, :controller => 'timelog', :except => :destroy do
218 member do
219 # Used when updating the edit form of an existing time entry
220 patch 'edit', :to => 'timelog#edit'
221 end
218 collection do
222 collection do
219 get 'report'
223 get 'report'
220 get 'bulk_edit'
224 get 'bulk_edit'
221 post 'bulk_update'
225 post 'bulk_update'
222 end
226 end
223 end
227 end
224 match '/time_entries/:id', :to => 'timelog#destroy', :via => :delete, :id => /\d+/
228 match '/time_entries/:id', :to => 'timelog#destroy', :via => :delete, :id => /\d+/
225 # TODO: delete /time_entries for bulk deletion
229 # TODO: delete /time_entries for bulk deletion
226 match '/time_entries/destroy', :to => 'timelog#destroy', :via => :delete
230 match '/time_entries/destroy', :to => 'timelog#destroy', :via => :delete
227 # Used to update the new time entry form
231 # Used to update the new time entry form
228 post '/time_entries/new', :to => 'timelog#new'
232 post '/time_entries/new', :to => 'timelog#new'
229
233
230 get 'projects/:id/activity', :to => 'activities#index', :as => :project_activity
234 get 'projects/:id/activity', :to => 'activities#index', :as => :project_activity
231 get 'activity', :to => 'activities#index'
235 get 'activity', :to => 'activities#index'
232
236
233 # repositories routes
237 # repositories routes
234 get 'projects/:id/repository/:repository_id/statistics', :to => 'repositories#stats'
238 get 'projects/:id/repository/:repository_id/statistics', :to => 'repositories#stats'
235 get 'projects/:id/repository/:repository_id/graph', :to => 'repositories#graph'
239 get 'projects/:id/repository/:repository_id/graph', :to => 'repositories#graph'
236
240
237 get 'projects/:id/repository/:repository_id/changes(/*path)',
241 get 'projects/:id/repository/:repository_id/changes(/*path)',
238 :to => 'repositories#changes',
242 :to => 'repositories#changes',
239 :format => false
243 :format => false
240
244
241 get 'projects/:id/repository/:repository_id/revisions/:rev', :to => 'repositories#revision'
245 get 'projects/:id/repository/:repository_id/revisions/:rev', :to => 'repositories#revision'
242 get 'projects/:id/repository/:repository_id/revision', :to => 'repositories#revision'
246 get 'projects/:id/repository/:repository_id/revision', :to => 'repositories#revision'
243 post 'projects/:id/repository/:repository_id/revisions/:rev/issues', :to => 'repositories#add_related_issue'
247 post 'projects/:id/repository/:repository_id/revisions/:rev/issues', :to => 'repositories#add_related_issue'
244 delete 'projects/:id/repository/:repository_id/revisions/:rev/issues/:issue_id', :to => 'repositories#remove_related_issue'
248 delete 'projects/:id/repository/:repository_id/revisions/:rev/issues/:issue_id', :to => 'repositories#remove_related_issue'
245 get 'projects/:id/repository/:repository_id/revisions', :to => 'repositories#revisions'
249 get 'projects/:id/repository/:repository_id/revisions', :to => 'repositories#revisions'
246 %w(browse show entry raw annotate diff).each do |action|
250 %w(browse show entry raw annotate diff).each do |action|
247 get "projects/:id/repository/:repository_id/revisions/:rev/#{action}(/*path)",
251 get "projects/:id/repository/:repository_id/revisions/:rev/#{action}(/*path)",
248 :controller => 'repositories',
252 :controller => 'repositories',
249 :action => action,
253 :action => action,
250 :format => false,
254 :format => false,
251 :constraints => {:rev => /[a-z0-9\.\-_]+/}
255 :constraints => {:rev => /[a-z0-9\.\-_]+/}
252 end
256 end
253
257
254 get 'projects/:id/repository/statistics', :to => 'repositories#stats'
258 get 'projects/:id/repository/statistics', :to => 'repositories#stats'
255 get 'projects/:id/repository/graph', :to => 'repositories#graph'
259 get 'projects/:id/repository/graph', :to => 'repositories#graph'
256
260
257 get 'projects/:id/repository/changes(/*path)',
261 get 'projects/:id/repository/changes(/*path)',
258 :to => 'repositories#changes',
262 :to => 'repositories#changes',
259 :format => false
263 :format => false
260
264
261 get 'projects/:id/repository/revisions', :to => 'repositories#revisions'
265 get 'projects/:id/repository/revisions', :to => 'repositories#revisions'
262 get 'projects/:id/repository/revisions/:rev', :to => 'repositories#revision'
266 get 'projects/:id/repository/revisions/:rev', :to => 'repositories#revision'
263 get 'projects/:id/repository/revision', :to => 'repositories#revision'
267 get 'projects/:id/repository/revision', :to => 'repositories#revision'
264 post 'projects/:id/repository/revisions/:rev/issues', :to => 'repositories#add_related_issue'
268 post 'projects/:id/repository/revisions/:rev/issues', :to => 'repositories#add_related_issue'
265 delete 'projects/:id/repository/revisions/:rev/issues/:issue_id', :to => 'repositories#remove_related_issue'
269 delete 'projects/:id/repository/revisions/:rev/issues/:issue_id', :to => 'repositories#remove_related_issue'
266 %w(browse show entry raw annotate diff).each do |action|
270 %w(browse show entry raw annotate diff).each do |action|
267 get "projects/:id/repository/revisions/:rev/#{action}(/*path)",
271 get "projects/:id/repository/revisions/:rev/#{action}(/*path)",
268 :controller => 'repositories',
272 :controller => 'repositories',
269 :action => action,
273 :action => action,
270 :format => false,
274 :format => false,
271 :constraints => {:rev => /[a-z0-9\.\-_]+/}
275 :constraints => {:rev => /[a-z0-9\.\-_]+/}
272 end
276 end
273 %w(browse entry raw changes annotate diff).each do |action|
277 %w(browse entry raw changes annotate diff).each do |action|
274 get "projects/:id/repository/:repository_id/#{action}(/*path)",
278 get "projects/:id/repository/:repository_id/#{action}(/*path)",
275 :controller => 'repositories',
279 :controller => 'repositories',
276 :action => action,
280 :action => action,
277 :format => false
281 :format => false
278 end
282 end
279 %w(browse entry raw changes annotate diff).each do |action|
283 %w(browse entry raw changes annotate diff).each do |action|
280 get "projects/:id/repository/#{action}(/*path)",
284 get "projects/:id/repository/#{action}(/*path)",
281 :controller => 'repositories',
285 :controller => 'repositories',
282 :action => action,
286 :action => action,
283 :format => false
287 :format => false
284 end
288 end
285
289
286 get 'projects/:id/repository/:repository_id/show/*path', :to => 'repositories#show', :format => false
290 get 'projects/:id/repository/:repository_id/show/*path', :to => 'repositories#show', :format => false
287 get 'projects/:id/repository/show/*path', :to => 'repositories#show', :format => false
291 get 'projects/:id/repository/show/*path', :to => 'repositories#show', :format => false
288
292
289 get 'projects/:id/repository/:repository_id', :to => 'repositories#show', :path => nil
293 get 'projects/:id/repository/:repository_id', :to => 'repositories#show', :path => nil
290 get 'projects/:id/repository', :to => 'repositories#show', :path => nil
294 get 'projects/:id/repository', :to => 'repositories#show', :path => nil
291
295
292 # additional routes for having the file name at the end of url
296 # additional routes for having the file name at the end of url
293 get 'attachments/:id/:filename', :to => 'attachments#show', :id => /\d+/, :filename => /.*/, :as => 'named_attachment'
297 get 'attachments/:id/:filename', :to => 'attachments#show', :id => /\d+/, :filename => /.*/, :as => 'named_attachment'
294 get 'attachments/download/:id/:filename', :to => 'attachments#download', :id => /\d+/, :filename => /.*/, :as => 'download_named_attachment'
298 get 'attachments/download/:id/:filename', :to => 'attachments#download', :id => /\d+/, :filename => /.*/, :as => 'download_named_attachment'
295 get 'attachments/download/:id', :to => 'attachments#download', :id => /\d+/
299 get 'attachments/download/:id', :to => 'attachments#download', :id => /\d+/
296 get 'attachments/thumbnail/:id(/:size)', :to => 'attachments#thumbnail', :id => /\d+/, :size => /\d+/, :as => 'thumbnail'
300 get 'attachments/thumbnail/:id(/:size)', :to => 'attachments#thumbnail', :id => /\d+/, :size => /\d+/, :as => 'thumbnail'
297 resources :attachments, :only => [:show, :update, :destroy]
301 resources :attachments, :only => [:show, :update, :destroy]
298 get 'attachments/:object_type/:object_id/edit', :to => 'attachments#edit_all', :as => :object_attachments_edit
302 get 'attachments/:object_type/:object_id/edit', :to => 'attachments#edit_all', :as => :object_attachments_edit
299 patch 'attachments/:object_type/:object_id', :to => 'attachments#update_all', :as => :object_attachments
303 patch 'attachments/:object_type/:object_id', :to => 'attachments#update_all', :as => :object_attachments
300
304
301 resources :groups do
305 resources :groups do
302 resources :memberships, :controller => 'principal_memberships'
306 resources :memberships, :controller => 'principal_memberships'
303 member do
307 member do
304 get 'autocomplete_for_user'
308 get 'autocomplete_for_user'
305 end
309 end
306 end
310 end
307
311
308 get 'groups/:id/users/new', :to => 'groups#new_users', :id => /\d+/, :as => 'new_group_users'
312 get 'groups/:id/users/new', :to => 'groups#new_users', :id => /\d+/, :as => 'new_group_users'
309 post 'groups/:id/users', :to => 'groups#add_users', :id => /\d+/, :as => 'group_users'
313 post 'groups/:id/users', :to => 'groups#add_users', :id => /\d+/, :as => 'group_users'
310 delete 'groups/:id/users/:user_id', :to => 'groups#remove_user', :id => /\d+/, :as => 'group_user'
314 delete 'groups/:id/users/:user_id', :to => 'groups#remove_user', :id => /\d+/, :as => 'group_user'
311
315
312 resources :trackers, :except => :show do
316 resources :trackers, :except => :show do
313 collection do
317 collection do
314 match 'fields', :via => [:get, :post]
318 match 'fields', :via => [:get, :post]
315 end
319 end
316 end
320 end
317 resources :issue_statuses, :except => :show do
321 resources :issue_statuses, :except => :show do
318 collection do
322 collection do
319 post 'update_issue_done_ratio'
323 post 'update_issue_done_ratio'
320 end
324 end
321 end
325 end
322 resources :custom_fields, :except => :show do
326 resources :custom_fields, :except => :show do
323 resources :enumerations, :controller => 'custom_field_enumerations', :except => [:show, :new, :edit]
327 resources :enumerations, :controller => 'custom_field_enumerations', :except => [:show, :new, :edit]
324 put 'enumerations', :to => 'custom_field_enumerations#update_each'
328 put 'enumerations', :to => 'custom_field_enumerations#update_each'
325 end
329 end
326 resources :roles do
330 resources :roles do
327 collection do
331 collection do
328 match 'permissions', :via => [:get, :post]
332 match 'permissions', :via => [:get, :post]
329 end
333 end
330 end
334 end
331 resources :enumerations, :except => :show
335 resources :enumerations, :except => :show
332 match 'enumerations/:type', :to => 'enumerations#index', :via => :get
336 match 'enumerations/:type', :to => 'enumerations#index', :via => :get
333
337
334 get 'projects/:id/search', :controller => 'search', :action => 'index'
338 get 'projects/:id/search', :controller => 'search', :action => 'index'
335 get 'search', :controller => 'search', :action => 'index'
339 get 'search', :controller => 'search', :action => 'index'
336
340
337
341
338 get 'mail_handler', :to => 'mail_handler#new'
342 get 'mail_handler', :to => 'mail_handler#new'
339 post 'mail_handler', :to => 'mail_handler#index'
343 post 'mail_handler', :to => 'mail_handler#index'
340
344
341 get 'admin', :to => 'admin#index'
345 get 'admin', :to => 'admin#index'
342 get 'admin/projects', :to => 'admin#projects'
346 get 'admin/projects', :to => 'admin#projects'
343 get 'admin/plugins', :to => 'admin#plugins'
347 get 'admin/plugins', :to => 'admin#plugins'
344 get 'admin/info', :to => 'admin#info'
348 get 'admin/info', :to => 'admin#info'
345 post 'admin/test_email', :to => 'admin#test_email', :as => 'test_email'
349 post 'admin/test_email', :to => 'admin#test_email', :as => 'test_email'
346 post 'admin/default_configuration', :to => 'admin#default_configuration'
350 post 'admin/default_configuration', :to => 'admin#default_configuration'
347
351
348 resources :auth_sources do
352 resources :auth_sources do
349 member do
353 member do
350 get 'test_connection', :as => 'try_connection'
354 get 'test_connection', :as => 'try_connection'
351 end
355 end
352 collection do
356 collection do
353 get 'autocomplete_for_new_user'
357 get 'autocomplete_for_new_user'
354 end
358 end
355 end
359 end
356
360
357 match 'workflows', :controller => 'workflows', :action => 'index', :via => :get
361 match 'workflows', :controller => 'workflows', :action => 'index', :via => :get
358 match 'workflows/edit', :controller => 'workflows', :action => 'edit', :via => [:get, :post]
362 match 'workflows/edit', :controller => 'workflows', :action => 'edit', :via => [:get, :post]
359 match 'workflows/permissions', :controller => 'workflows', :action => 'permissions', :via => [:get, :post]
363 match 'workflows/permissions', :controller => 'workflows', :action => 'permissions', :via => [:get, :post]
360 match 'workflows/copy', :controller => 'workflows', :action => 'copy', :via => [:get, :post]
364 match 'workflows/copy', :controller => 'workflows', :action => 'copy', :via => [:get, :post]
361 match 'settings', :controller => 'settings', :action => 'index', :via => :get
365 match 'settings', :controller => 'settings', :action => 'index', :via => :get
362 match 'settings/edit', :controller => 'settings', :action => 'edit', :via => [:get, :post]
366 match 'settings/edit', :controller => 'settings', :action => 'edit', :via => [:get, :post]
363 match 'settings/plugin/:id', :controller => 'settings', :action => 'plugin', :via => [:get, :post], :as => 'plugin_settings'
367 match 'settings/plugin/:id', :controller => 'settings', :action => 'plugin', :via => [:get, :post], :as => 'plugin_settings'
364
368
365 match 'sys/projects', :to => 'sys#projects', :via => :get
369 match 'sys/projects', :to => 'sys#projects', :via => :get
366 match 'sys/projects/:id/repository', :to => 'sys#create_project_repository', :via => :post
370 match 'sys/projects/:id/repository', :to => 'sys#create_project_repository', :via => :post
367 match 'sys/fetch_changesets', :to => 'sys#fetch_changesets', :via => [:get, :post]
371 match 'sys/fetch_changesets', :to => 'sys#fetch_changesets', :via => [:get, :post]
368
372
369 match 'uploads', :to => 'attachments#upload', :via => :post
373 match 'uploads', :to => 'attachments#upload', :via => :post
370
374
371 get 'robots.txt', :to => 'welcome#robots'
375 get 'robots.txt', :to => 'welcome#robots'
372
376
373 Dir.glob File.expand_path("plugins/*", Rails.root) do |plugin_dir|
377 Dir.glob File.expand_path("plugins/*", Rails.root) do |plugin_dir|
374 file = File.join(plugin_dir, "config/routes.rb")
378 file = File.join(plugin_dir, "config/routes.rb")
375 if File.exists?(file)
379 if File.exists?(file)
376 begin
380 begin
377 instance_eval File.read(file)
381 instance_eval File.read(file)
378 rescue Exception => e
382 rescue Exception => e
379 puts "An error occurred while loading the routes definition of #{File.basename(plugin_dir)} plugin (#{file}): #{e.message}."
383 puts "An error occurred while loading the routes definition of #{File.basename(plugin_dir)} plugin (#{file}): #{e.message}."
380 exit 1
384 exit 1
381 end
385 end
382 end
386 end
383 end
387 end
384 end
388 end
@@ -1,1018 +1,1020
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # Redmine - project management software
2 # Redmine - project management software
3 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 # Copyright (C) 2006-2016 Jean-Philippe Lang
4 #
4 #
5 # This program is free software; you can redistribute it and/or
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
8 # of the License, or (at your option) any later version.
9 #
9 #
10 # This program is distributed in the hope that it will be useful,
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
13 # GNU General Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
18
19 require File.expand_path('../../test_helper', __FILE__)
19 require File.expand_path('../../test_helper', __FILE__)
20
20
21 class TimelogControllerTest < Redmine::ControllerTest
21 class TimelogControllerTest < Redmine::ControllerTest
22 fixtures :projects, :enabled_modules, :roles, :members,
22 fixtures :projects, :enabled_modules, :roles, :members,
23 :member_roles, :issues, :time_entries, :users,
23 :member_roles, :issues, :time_entries, :users,
24 :trackers, :enumerations, :issue_statuses,
24 :trackers, :enumerations, :issue_statuses,
25 :custom_fields, :custom_values,
25 :custom_fields, :custom_values,
26 :projects_trackers, :custom_fields_trackers,
26 :projects_trackers, :custom_fields_trackers,
27 :custom_fields_projects
27 :custom_fields_projects
28
28
29 include Redmine::I18n
29 include Redmine::I18n
30
30
31 def test_new
31 def test_new
32 @request.session[:user_id] = 3
32 @request.session[:user_id] = 3
33 get :new
33 get :new
34 assert_response :success
34 assert_response :success
35
35
36 assert_select 'input[name=?][type=hidden]', 'project_id', 0
36 assert_select 'input[name=?][type=hidden]', 'project_id', 0
37 assert_select 'input[name=?][type=hidden]', 'issue_id', 0
37 assert_select 'input[name=?][type=hidden]', 'issue_id', 0
38 assert_select 'span[id=?]', 'time_entry_issue'
38 assert_select 'select[name=?]', 'time_entry[project_id]' do
39 assert_select 'select[name=?]', 'time_entry[project_id]' do
39 # blank option for project
40 # blank option for project
40 assert_select 'option[value=""]'
41 assert_select 'option[value=""]'
41 end
42 end
42 end
43 end
43
44
44 def test_new_with_project_id
45 def test_new_with_project_id
45 @request.session[:user_id] = 3
46 @request.session[:user_id] = 3
46 get :new, :params => {:project_id => 1}
47 get :new, :params => {:project_id => 1}
47 assert_response :success
48 assert_response :success
48
49
49 assert_select 'input[name=?][type=hidden]', 'project_id'
50 assert_select 'input[name=?][type=hidden]', 'project_id'
50 assert_select 'input[name=?][type=hidden]', 'issue_id', 0
51 assert_select 'input[name=?][type=hidden]', 'issue_id', 0
51 assert_select 'select[name=?]', 'time_entry[project_id]', 0
52 assert_select 'select[name=?]', 'time_entry[project_id]', 0
52 end
53 end
53
54
54 def test_new_with_issue_id
55 def test_new_with_issue_id
55 @request.session[:user_id] = 3
56 @request.session[:user_id] = 3
56 get :new, :params => {:issue_id => 2}
57 get :new, :params => {:issue_id => 2}
57 assert_response :success
58 assert_response :success
58
59
59 assert_select 'input[name=?][type=hidden]', 'project_id', 0
60 assert_select 'input[name=?][type=hidden]', 'project_id', 0
60 assert_select 'input[name=?][type=hidden]', 'issue_id'
61 assert_select 'input[name=?][type=hidden]', 'issue_id'
62 assert_select 'a[href=?]', '/issues/2', :text => /Feature request #2/
61 assert_select 'select[name=?]', 'time_entry[project_id]', 0
63 assert_select 'select[name=?]', 'time_entry[project_id]', 0
62 end
64 end
63
65
64 def test_new_without_project_should_prefill_the_form
66 def test_new_without_project_should_prefill_the_form
65 @request.session[:user_id] = 3
67 @request.session[:user_id] = 3
66 get :new, :params => {:time_entry => {:project_id => '1'}}
68 get :new, :params => {:time_entry => {:project_id => '1'}}
67 assert_response :success
69 assert_response :success
68
70
69 assert_select 'select[name=?]', 'time_entry[project_id]' do
71 assert_select 'select[name=?]', 'time_entry[project_id]' do
70 assert_select 'option[value="1"][selected=selected]'
72 assert_select 'option[value="1"][selected=selected]'
71 end
73 end
72 end
74 end
73
75
74 def test_new_without_project_should_deny_without_permission
76 def test_new_without_project_should_deny_without_permission
75 Role.all.each {|role| role.remove_permission! :log_time}
77 Role.all.each {|role| role.remove_permission! :log_time}
76 @request.session[:user_id] = 3
78 @request.session[:user_id] = 3
77
79
78 get :new
80 get :new
79 assert_response 403
81 assert_response 403
80 end
82 end
81
83
82 def test_new_should_select_default_activity
84 def test_new_should_select_default_activity
83 @request.session[:user_id] = 3
85 @request.session[:user_id] = 3
84 get :new, :params => {:project_id => 1}
86 get :new, :params => {:project_id => 1}
85 assert_response :success
87 assert_response :success
86 assert_select 'select[name=?]', 'time_entry[activity_id]' do
88 assert_select 'select[name=?]', 'time_entry[activity_id]' do
87 assert_select 'option[selected=selected]', :text => 'Development'
89 assert_select 'option[selected=selected]', :text => 'Development'
88 end
90 end
89 end
91 end
90
92
91 def test_new_should_only_show_active_time_entry_activities
93 def test_new_should_only_show_active_time_entry_activities
92 @request.session[:user_id] = 3
94 @request.session[:user_id] = 3
93 get :new, :params => {:project_id => 1}
95 get :new, :params => {:project_id => 1}
94 assert_response :success
96 assert_response :success
95 assert_select 'option', :text => 'Inactive Activity', :count => 0
97 assert_select 'option', :text => 'Inactive Activity', :count => 0
96 end
98 end
97
99
98 def test_post_new_as_js_should_update_activity_options
100 def test_post_new_as_js_should_update_activity_options
99 @request.session[:user_id] = 3
101 @request.session[:user_id] = 3
100 post :new, :params => {:time_entry => {:project_id => 1}, :format => 'js'}
102 post :new, :params => {:time_entry => {:project_id => 1}, :format => 'js'}
101 assert_response :success
103 assert_response :success
102 assert_include '#time_entry_activity_id', response.body
104 assert_include '#time_entry_activity_id', response.body
103 end
105 end
104
106
105 def test_get_edit_existing_time
107 def test_get_edit_existing_time
106 @request.session[:user_id] = 2
108 @request.session[:user_id] = 2
107 get :edit, :params => {:id => 2, :project_id => nil}
109 get :edit, :params => {:id => 2, :project_id => nil}
108 assert_response :success
110 assert_response :success
109
111
110 assert_select 'form[action=?]', '/time_entries/2'
112 assert_select 'form[action=?]', '/time_entries/2'
111 end
113 end
112
114
113 def test_get_edit_with_an_existing_time_entry_with_inactive_activity
115 def test_get_edit_with_an_existing_time_entry_with_inactive_activity
114 te = TimeEntry.find(1)
116 te = TimeEntry.find(1)
115 te.activity = TimeEntryActivity.find_by_name("Inactive Activity")
117 te.activity = TimeEntryActivity.find_by_name("Inactive Activity")
116 te.save!(:validate => false)
118 te.save!(:validate => false)
117
119
118 @request.session[:user_id] = 1
120 @request.session[:user_id] = 1
119 get :edit, :params => {:project_id => 1, :id => 1}
121 get :edit, :params => {:project_id => 1, :id => 1}
120 assert_response :success
122 assert_response :success
121
123
122 # Blank option since nothing is pre-selected
124 # Blank option since nothing is pre-selected
123 assert_select 'option', :text => '--- Please select ---'
125 assert_select 'option', :text => '--- Please select ---'
124 end
126 end
125
127
126 def test_post_create
128 def test_post_create
127 @request.session[:user_id] = 3
129 @request.session[:user_id] = 3
128 assert_difference 'TimeEntry.count' do
130 assert_difference 'TimeEntry.count' do
129 post :create, :params => {
131 post :create, :params => {
130 :project_id => 1,
132 :project_id => 1,
131 :time_entry => {:comments => 'Some work on TimelogControllerTest',
133 :time_entry => {:comments => 'Some work on TimelogControllerTest',
132 # Not the default activity
134 # Not the default activity
133 :activity_id => '11',
135 :activity_id => '11',
134 :spent_on => '2008-03-14',
136 :spent_on => '2008-03-14',
135 :issue_id => '1',
137 :issue_id => '1',
136 :hours => '7.3'
138 :hours => '7.3'
137 }
139 }
138 }
140 }
139 assert_redirected_to '/projects/ecookbook/time_entries'
141 assert_redirected_to '/projects/ecookbook/time_entries'
140 end
142 end
141
143
142 t = TimeEntry.order('id DESC').first
144 t = TimeEntry.order('id DESC').first
143 assert_not_nil t
145 assert_not_nil t
144 assert_equal 'Some work on TimelogControllerTest', t.comments
146 assert_equal 'Some work on TimelogControllerTest', t.comments
145 assert_equal 1, t.project_id
147 assert_equal 1, t.project_id
146 assert_equal 1, t.issue_id
148 assert_equal 1, t.issue_id
147 assert_equal 11, t.activity_id
149 assert_equal 11, t.activity_id
148 assert_equal 7.3, t.hours
150 assert_equal 7.3, t.hours
149 assert_equal 3, t.user_id
151 assert_equal 3, t.user_id
150 end
152 end
151
153
152 def test_post_create_with_blank_issue
154 def test_post_create_with_blank_issue
153 @request.session[:user_id] = 3
155 @request.session[:user_id] = 3
154 assert_difference 'TimeEntry.count' do
156 assert_difference 'TimeEntry.count' do
155 post :create, :params => {
157 post :create, :params => {
156 :project_id => 1,
158 :project_id => 1,
157 :time_entry => {
159 :time_entry => {
158 :comments => 'Some work on TimelogControllerTest',
160 :comments => 'Some work on TimelogControllerTest',
159 # Not the default activity
161 # Not the default activity
160 :activity_id => '11',
162 :activity_id => '11',
161 :issue_id => '',
163 :issue_id => '',
162 :spent_on => '2008-03-14',
164 :spent_on => '2008-03-14',
163 :hours => '7.3'
165 :hours => '7.3'
164 }
166 }
165 }
167 }
166 assert_redirected_to '/projects/ecookbook/time_entries'
168 assert_redirected_to '/projects/ecookbook/time_entries'
167 end
169 end
168
170
169 t = TimeEntry.order('id DESC').first
171 t = TimeEntry.order('id DESC').first
170 assert_not_nil t
172 assert_not_nil t
171 assert_equal 'Some work on TimelogControllerTest', t.comments
173 assert_equal 'Some work on TimelogControllerTest', t.comments
172 assert_equal 1, t.project_id
174 assert_equal 1, t.project_id
173 assert_nil t.issue_id
175 assert_nil t.issue_id
174 assert_equal 11, t.activity_id
176 assert_equal 11, t.activity_id
175 assert_equal 7.3, t.hours
177 assert_equal 7.3, t.hours
176 assert_equal 3, t.user_id
178 assert_equal 3, t.user_id
177 end
179 end
178
180
179 def test_create_on_project_with_time_tracking_disabled_should_fail
181 def test_create_on_project_with_time_tracking_disabled_should_fail
180 Project.find(1).disable_module! :time_tracking
182 Project.find(1).disable_module! :time_tracking
181
183
182 @request.session[:user_id] = 2
184 @request.session[:user_id] = 2
183 assert_no_difference 'TimeEntry.count' do
185 assert_no_difference 'TimeEntry.count' do
184 post :create, :params => {
186 post :create, :params => {
185 :time_entry => {
187 :time_entry => {
186 :project_id => '1', :issue_id => '',
188 :project_id => '1', :issue_id => '',
187 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
189 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
188 }
190 }
189 }
191 }
190 end
192 end
191 end
193 end
192
194
193 def test_create_on_project_without_permission_should_fail
195 def test_create_on_project_without_permission_should_fail
194 Role.find(1).remove_permission! :log_time
196 Role.find(1).remove_permission! :log_time
195
197
196 @request.session[:user_id] = 2
198 @request.session[:user_id] = 2
197 assert_no_difference 'TimeEntry.count' do
199 assert_no_difference 'TimeEntry.count' do
198 post :create, :params => {
200 post :create, :params => {
199 :time_entry => {
201 :time_entry => {
200 :project_id => '1', :issue_id => '',
202 :project_id => '1', :issue_id => '',
201 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
203 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
202 }
204 }
203 }
205 }
204 end
206 end
205 end
207 end
206
208
207 def test_create_on_issue_in_project_with_time_tracking_disabled_should_fail
209 def test_create_on_issue_in_project_with_time_tracking_disabled_should_fail
208 Project.find(1).disable_module! :time_tracking
210 Project.find(1).disable_module! :time_tracking
209
211
210 @request.session[:user_id] = 2
212 @request.session[:user_id] = 2
211 assert_no_difference 'TimeEntry.count' do
213 assert_no_difference 'TimeEntry.count' do
212 post :create, :params => {
214 post :create, :params => {
213 :time_entry => {
215 :time_entry => {
214 :project_id => '', :issue_id => '1',
216 :project_id => '', :issue_id => '1',
215 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
217 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
216 }
218 }
217 }
219 }
218 assert_select_error /Issue is invalid/
220 assert_select_error /Issue is invalid/
219 end
221 end
220 end
222 end
221
223
222 def test_create_on_issue_in_project_without_permission_should_fail
224 def test_create_on_issue_in_project_without_permission_should_fail
223 Role.find(1).remove_permission! :log_time
225 Role.find(1).remove_permission! :log_time
224
226
225 @request.session[:user_id] = 2
227 @request.session[:user_id] = 2
226 assert_no_difference 'TimeEntry.count' do
228 assert_no_difference 'TimeEntry.count' do
227 post :create, :params => {
229 post :create, :params => {
228 :time_entry => {
230 :time_entry => {
229 :project_id => '', :issue_id => '1',
231 :project_id => '', :issue_id => '1',
230 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
232 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
231 }
233 }
232 }
234 }
233 assert_select_error /Issue is invalid/
235 assert_select_error /Issue is invalid/
234 end
236 end
235 end
237 end
236
238
237 def test_create_on_issue_that_is_not_visible_should_not_disclose_subject
239 def test_create_on_issue_that_is_not_visible_should_not_disclose_subject
238 issue = Issue.generate!(:subject => "issue_that_is_not_visible", :is_private => true)
240 issue = Issue.generate!(:subject => "issue_that_is_not_visible", :is_private => true)
239 assert !issue.visible?(User.find(3))
241 assert !issue.visible?(User.find(3))
240
242
241 @request.session[:user_id] = 3
243 @request.session[:user_id] = 3
242 assert_no_difference 'TimeEntry.count' do
244 assert_no_difference 'TimeEntry.count' do
243 post :create, :params => {
245 post :create, :params => {
244 :time_entry => {
246 :time_entry => {
245 :project_id => '', :issue_id => issue.id.to_s,
247 :project_id => '', :issue_id => issue.id.to_s,
246 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
248 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
247 }
249 }
248 }
250 }
249 end
251 end
250 assert_select_error /Issue is invalid/
252 assert_select_error /Issue is invalid/
251 assert_select "input[name=?][value=?]", "time_entry[issue_id]", issue.id.to_s
253 assert_select "input[name=?][value=?]", "time_entry[issue_id]", issue.id.to_s
252 assert_select "#time_entry_issue", 0
254 assert_select "#time_entry_issue a", 0
253 assert !response.body.include?('issue_that_is_not_visible')
255 assert !response.body.include?('issue_that_is_not_visible')
254 end
256 end
255
257
256 def test_create_and_continue_at_project_level
258 def test_create_and_continue_at_project_level
257 @request.session[:user_id] = 2
259 @request.session[:user_id] = 2
258 assert_difference 'TimeEntry.count' do
260 assert_difference 'TimeEntry.count' do
259 post :create, :params => {
261 post :create, :params => {
260 :time_entry => {
262 :time_entry => {
261 :project_id => '1',
263 :project_id => '1',
262 :activity_id => '11',
264 :activity_id => '11',
263 :issue_id => '',
265 :issue_id => '',
264 :spent_on => '2008-03-14',
266 :spent_on => '2008-03-14',
265 :hours => '7.3'
267 :hours => '7.3'
266 },
268 },
267 :continue => '1'
269 :continue => '1'
268 }
270 }
269 assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D=1'
271 assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D=1'
270 end
272 end
271 end
273 end
272
274
273 def test_create_and_continue_at_issue_level
275 def test_create_and_continue_at_issue_level
274 @request.session[:user_id] = 2
276 @request.session[:user_id] = 2
275 assert_difference 'TimeEntry.count' do
277 assert_difference 'TimeEntry.count' do
276 post :create, :params => {
278 post :create, :params => {
277 :time_entry => {
279 :time_entry => {
278 :project_id => '',
280 :project_id => '',
279 :activity_id => '11',
281 :activity_id => '11',
280 :issue_id => '1',
282 :issue_id => '1',
281 :spent_on => '2008-03-14',
283 :spent_on => '2008-03-14',
282 :hours => '7.3'
284 :hours => '7.3'
283 },
285 },
284 :continue => '1'
286 :continue => '1'
285 }
287 }
286 assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1&time_entry%5Bproject_id%5D='
288 assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1&time_entry%5Bproject_id%5D='
287 end
289 end
288 end
290 end
289
291
290 def test_create_and_continue_with_project_id
292 def test_create_and_continue_with_project_id
291 @request.session[:user_id] = 2
293 @request.session[:user_id] = 2
292 assert_difference 'TimeEntry.count' do
294 assert_difference 'TimeEntry.count' do
293 post :create, :params => {
295 post :create, :params => {
294 :project_id => 1,
296 :project_id => 1,
295 :time_entry => {
297 :time_entry => {
296 :activity_id => '11',
298 :activity_id => '11',
297 :issue_id => '',
299 :issue_id => '',
298 :spent_on => '2008-03-14',
300 :spent_on => '2008-03-14',
299 :hours => '7.3'
301 :hours => '7.3'
300 },
302 },
301 :continue => '1'
303 :continue => '1'
302 }
304 }
303 assert_redirected_to '/projects/ecookbook/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D='
305 assert_redirected_to '/projects/ecookbook/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D='
304 end
306 end
305 end
307 end
306
308
307 def test_create_and_continue_with_issue_id
309 def test_create_and_continue_with_issue_id
308 @request.session[:user_id] = 2
310 @request.session[:user_id] = 2
309 assert_difference 'TimeEntry.count' do
311 assert_difference 'TimeEntry.count' do
310 post :create, :params => {
312 post :create, :params => {
311 :issue_id => 1,
313 :issue_id => 1,
312 :time_entry => {
314 :time_entry => {
313 :activity_id => '11',
315 :activity_id => '11',
314 :issue_id => '1',
316 :issue_id => '1',
315 :spent_on => '2008-03-14',
317 :spent_on => '2008-03-14',
316 :hours => '7.3'
318 :hours => '7.3'
317 },
319 },
318 :continue => '1'
320 :continue => '1'
319 }
321 }
320 assert_redirected_to '/issues/1/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1&time_entry%5Bproject_id%5D='
322 assert_redirected_to '/issues/1/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1&time_entry%5Bproject_id%5D='
321 end
323 end
322 end
324 end
323
325
324 def test_create_without_log_time_permission_should_be_denied
326 def test_create_without_log_time_permission_should_be_denied
325 @request.session[:user_id] = 2
327 @request.session[:user_id] = 2
326 Role.find_by_name('Manager').remove_permission! :log_time
328 Role.find_by_name('Manager').remove_permission! :log_time
327 post :create, :params => {
329 post :create, :params => {
328 :project_id => 1,
330 :project_id => 1,
329 :time_entry => {
331 :time_entry => {
330 :activity_id => '11',
332 :activity_id => '11',
331 :issue_id => '',
333 :issue_id => '',
332 :spent_on => '2008-03-14',
334 :spent_on => '2008-03-14',
333 :hours => '7.3'
335 :hours => '7.3'
334 }
336 }
335 }
337 }
336 assert_response 403
338 assert_response 403
337 end
339 end
338
340
339 def test_create_without_project_and_issue_should_fail
341 def test_create_without_project_and_issue_should_fail
340 @request.session[:user_id] = 2
342 @request.session[:user_id] = 2
341 post :create, :params => {:time_entry => {:issue_id => ''}}
343 post :create, :params => {:time_entry => {:issue_id => ''}}
342
344
343 assert_response :success
345 assert_response :success
344 assert_select_error /Project cannot be blank/
346 assert_select_error /Project cannot be blank/
345 end
347 end
346
348
347 def test_create_with_failure
349 def test_create_with_failure
348 @request.session[:user_id] = 2
350 @request.session[:user_id] = 2
349 post :create, :params => {
351 post :create, :params => {
350 :project_id => 1,
352 :project_id => 1,
351 :time_entry => {
353 :time_entry => {
352 :activity_id => '',
354 :activity_id => '',
353 :issue_id => '',
355 :issue_id => '',
354 :spent_on => '2008-03-14',
356 :spent_on => '2008-03-14',
355 :hours => '7.3'
357 :hours => '7.3'
356 }
358 }
357 }
359 }
358 assert_response :success
360 assert_response :success
359 end
361 end
360
362
361 def test_create_without_project
363 def test_create_without_project
362 @request.session[:user_id] = 2
364 @request.session[:user_id] = 2
363 assert_difference 'TimeEntry.count' do
365 assert_difference 'TimeEntry.count' do
364 post :create, :params => {
366 post :create, :params => {
365 :time_entry => {
367 :time_entry => {
366 :project_id => '1',
368 :project_id => '1',
367 :activity_id => '11',
369 :activity_id => '11',
368 :issue_id => '',
370 :issue_id => '',
369 :spent_on => '2008-03-14',
371 :spent_on => '2008-03-14',
370 :hours => '7.3'
372 :hours => '7.3'
371 }
373 }
372 }
374 }
373 end
375 end
374
376
375 assert_redirected_to '/projects/ecookbook/time_entries'
377 assert_redirected_to '/projects/ecookbook/time_entries'
376 time_entry = TimeEntry.order('id DESC').first
378 time_entry = TimeEntry.order('id DESC').first
377 assert_equal 1, time_entry.project_id
379 assert_equal 1, time_entry.project_id
378 end
380 end
379
381
380 def test_create_without_project_should_fail_with_issue_not_inside_project
382 def test_create_without_project_should_fail_with_issue_not_inside_project
381 @request.session[:user_id] = 2
383 @request.session[:user_id] = 2
382 assert_no_difference 'TimeEntry.count' do
384 assert_no_difference 'TimeEntry.count' do
383 post :create, :params => {
385 post :create, :params => {
384 :time_entry => {
386 :time_entry => {
385 :project_id => '1',
387 :project_id => '1',
386 :activity_id => '11',
388 :activity_id => '11',
387 :issue_id => '5',
389 :issue_id => '5',
388 :spent_on => '2008-03-14',
390 :spent_on => '2008-03-14',
389 :hours => '7.3'
391 :hours => '7.3'
390 }
392 }
391 }
393 }
392 end
394 end
393
395
394 assert_response :success
396 assert_response :success
395 assert_select_error /Issue is invalid/
397 assert_select_error /Issue is invalid/
396 end
398 end
397
399
398 def test_create_without_project_should_deny_without_permission
400 def test_create_without_project_should_deny_without_permission
399 @request.session[:user_id] = 2
401 @request.session[:user_id] = 2
400 Project.find(3).disable_module!(:time_tracking)
402 Project.find(3).disable_module!(:time_tracking)
401
403
402 assert_no_difference 'TimeEntry.count' do
404 assert_no_difference 'TimeEntry.count' do
403 post :create, :params => {
405 post :create, :params => {
404 :time_entry => {
406 :time_entry => {
405 :project_id => '3',
407 :project_id => '3',
406 :activity_id => '11',
408 :activity_id => '11',
407 :issue_id => '',
409 :issue_id => '',
408 :spent_on => '2008-03-14',
410 :spent_on => '2008-03-14',
409 :hours => '7.3'
411 :hours => '7.3'
410 }
412 }
411 }
413 }
412 end
414 end
413
415
414 assert_response 403
416 assert_response 403
415 end
417 end
416
418
417 def test_create_without_project_with_failure
419 def test_create_without_project_with_failure
418 @request.session[:user_id] = 2
420 @request.session[:user_id] = 2
419 assert_no_difference 'TimeEntry.count' do
421 assert_no_difference 'TimeEntry.count' do
420 post :create, :params => {
422 post :create, :params => {
421 :time_entry => {
423 :time_entry => {
422 :project_id => '1',
424 :project_id => '1',
423 :activity_id => '11',
425 :activity_id => '11',
424 :issue_id => '',
426 :issue_id => '',
425 :spent_on => '2008-03-14',
427 :spent_on => '2008-03-14',
426 :hours => ''
428 :hours => ''
427 }
429 }
428 }
430 }
429 end
431 end
430
432
431 assert_response :success
433 assert_response :success
432 assert_select 'select[name=?]', 'time_entry[project_id]' do
434 assert_select 'select[name=?]', 'time_entry[project_id]' do
433 assert_select 'option[value="1"][selected=selected]'
435 assert_select 'option[value="1"][selected=selected]'
434 end
436 end
435 end
437 end
436
438
437 def test_update
439 def test_update
438 entry = TimeEntry.find(1)
440 entry = TimeEntry.find(1)
439 assert_equal 1, entry.issue_id
441 assert_equal 1, entry.issue_id
440 assert_equal 2, entry.user_id
442 assert_equal 2, entry.user_id
441
443
442 @request.session[:user_id] = 1
444 @request.session[:user_id] = 1
443 put :update, :params => {
445 put :update, :params => {
444 :id => 1,
446 :id => 1,
445 :time_entry => {
447 :time_entry => {
446 :issue_id => '2',
448 :issue_id => '2',
447 :hours => '8'
449 :hours => '8'
448 }
450 }
449 }
451 }
450 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
452 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
451 entry.reload
453 entry.reload
452
454
453 assert_equal 8, entry.hours
455 assert_equal 8, entry.hours
454 assert_equal 2, entry.issue_id
456 assert_equal 2, entry.issue_id
455 assert_equal 2, entry.user_id
457 assert_equal 2, entry.user_id
456 end
458 end
457
459
458 def test_update_should_allow_to_change_issue_to_another_project
460 def test_update_should_allow_to_change_issue_to_another_project
459 entry = TimeEntry.generate!(:issue_id => 1)
461 entry = TimeEntry.generate!(:issue_id => 1)
460
462
461 @request.session[:user_id] = 1
463 @request.session[:user_id] = 1
462 put :update, :params => {
464 put :update, :params => {
463 :id => entry.id,
465 :id => entry.id,
464 :time_entry => {
466 :time_entry => {
465 :issue_id => '5'
467 :issue_id => '5'
466 }
468 }
467 }
469 }
468 assert_response 302
470 assert_response 302
469 entry.reload
471 entry.reload
470
472
471 assert_equal 5, entry.issue_id
473 assert_equal 5, entry.issue_id
472 assert_equal 3, entry.project_id
474 assert_equal 3, entry.project_id
473 end
475 end
474
476
475 def test_update_should_not_allow_to_change_issue_to_an_invalid_project
477 def test_update_should_not_allow_to_change_issue_to_an_invalid_project
476 entry = TimeEntry.generate!(:issue_id => 1)
478 entry = TimeEntry.generate!(:issue_id => 1)
477 Project.find(3).disable_module!(:time_tracking)
479 Project.find(3).disable_module!(:time_tracking)
478
480
479 @request.session[:user_id] = 1
481 @request.session[:user_id] = 1
480 put :update, :params => {
482 put :update, :params => {
481 :id => entry.id,
483 :id => entry.id,
482 :time_entry => {
484 :time_entry => {
483 :issue_id => '5'
485 :issue_id => '5'
484 }
486 }
485 }
487 }
486 assert_response :success
488 assert_response :success
487 assert_select_error /Issue is invalid/
489 assert_select_error /Issue is invalid/
488 end
490 end
489
491
490 def test_get_bulk_edit
492 def test_get_bulk_edit
491 @request.session[:user_id] = 2
493 @request.session[:user_id] = 2
492
494
493 get :bulk_edit, :params => {:ids => [1, 2]}
495 get :bulk_edit, :params => {:ids => [1, 2]}
494 assert_response :success
496 assert_response :success
495
497
496 assert_select 'ul#bulk-selection' do
498 assert_select 'ul#bulk-selection' do
497 assert_select 'li', 2
499 assert_select 'li', 2
498 assert_select 'li a', :text => '03/23/2007 - eCookbook: 4.25 hours'
500 assert_select 'li a', :text => '03/23/2007 - eCookbook: 4.25 hours'
499 end
501 end
500
502
501 assert_select 'form#bulk_edit_form[action=?]', '/time_entries/bulk_update' do
503 assert_select 'form#bulk_edit_form[action=?]', '/time_entries/bulk_update' do
502 # System wide custom field
504 # System wide custom field
503 assert_select 'select[name=?]', 'time_entry[custom_field_values][10]'
505 assert_select 'select[name=?]', 'time_entry[custom_field_values][10]'
504
506
505 # Activities
507 # Activities
506 assert_select 'select[name=?]', 'time_entry[activity_id]' do
508 assert_select 'select[name=?]', 'time_entry[activity_id]' do
507 assert_select 'option[value=""]', :text => '(No change)'
509 assert_select 'option[value=""]', :text => '(No change)'
508 assert_select 'option[value="9"]', :text => 'Design'
510 assert_select 'option[value="9"]', :text => 'Design'
509 end
511 end
510 end
512 end
511 end
513 end
512
514
513 def test_get_bulk_edit_on_different_projects
515 def test_get_bulk_edit_on_different_projects
514 @request.session[:user_id] = 2
516 @request.session[:user_id] = 2
515
517
516 get :bulk_edit, :params => {:ids => [1, 2, 6]}
518 get :bulk_edit, :params => {:ids => [1, 2, 6]}
517 assert_response :success
519 assert_response :success
518 end
520 end
519
521
520 def test_bulk_edit_with_edit_own_time_entries_permission
522 def test_bulk_edit_with_edit_own_time_entries_permission
521 @request.session[:user_id] = 2
523 @request.session[:user_id] = 2
522 Role.find_by_name('Manager').remove_permission! :edit_time_entries
524 Role.find_by_name('Manager').remove_permission! :edit_time_entries
523 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
525 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
524 ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
526 ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
525
527
526 get :bulk_edit, :params => {:ids => ids}
528 get :bulk_edit, :params => {:ids => ids}
527 assert_response :success
529 assert_response :success
528 end
530 end
529
531
530 def test_bulk_update
532 def test_bulk_update
531 @request.session[:user_id] = 2
533 @request.session[:user_id] = 2
532 # update time entry activity
534 # update time entry activity
533 post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :activity_id => 9}}
535 post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :activity_id => 9}}
534
536
535 assert_response 302
537 assert_response 302
536 # check that the issues were updated
538 # check that the issues were updated
537 assert_equal [9, 9], TimeEntry.where(:id => [1, 2]).collect {|i| i.activity_id}
539 assert_equal [9, 9], TimeEntry.where(:id => [1, 2]).collect {|i| i.activity_id}
538 end
540 end
539
541
540 def test_bulk_update_with_failure
542 def test_bulk_update_with_failure
541 @request.session[:user_id] = 2
543 @request.session[:user_id] = 2
542 post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :hours => 'A'}}
544 post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :hours => 'A'}}
543
545
544 assert_response 302
546 assert_response 302
545 assert_match /Failed to save 2 time entrie/, flash[:error]
547 assert_match /Failed to save 2 time entrie/, flash[:error]
546 end
548 end
547
549
548 def test_bulk_update_on_different_projects
550 def test_bulk_update_on_different_projects
549 @request.session[:user_id] = 2
551 @request.session[:user_id] = 2
550 # makes user a manager on the other project
552 # makes user a manager on the other project
551 Member.create!(:user_id => 2, :project_id => 3, :role_ids => [1])
553 Member.create!(:user_id => 2, :project_id => 3, :role_ids => [1])
552
554
553 # update time entry activity
555 # update time entry activity
554 post :bulk_update, :params => {:ids => [1, 2, 4], :time_entry => { :activity_id => 9 }}
556 post :bulk_update, :params => {:ids => [1, 2, 4], :time_entry => { :activity_id => 9 }}
555
557
556 assert_response 302
558 assert_response 302
557 # check that the issues were updated
559 # check that the issues were updated
558 assert_equal [9, 9, 9], TimeEntry.where(:id => [1, 2, 4]).collect {|i| i.activity_id}
560 assert_equal [9, 9, 9], TimeEntry.where(:id => [1, 2, 4]).collect {|i| i.activity_id}
559 end
561 end
560
562
561 def test_bulk_update_on_different_projects_without_rights
563 def test_bulk_update_on_different_projects_without_rights
562 @request.session[:user_id] = 3
564 @request.session[:user_id] = 3
563 user = User.find(3)
565 user = User.find(3)
564 action = { :controller => "timelog", :action => "bulk_update" }
566 action = { :controller => "timelog", :action => "bulk_update" }
565 assert user.allowed_to?(action, TimeEntry.find(1).project)
567 assert user.allowed_to?(action, TimeEntry.find(1).project)
566 assert ! user.allowed_to?(action, TimeEntry.find(5).project)
568 assert ! user.allowed_to?(action, TimeEntry.find(5).project)
567
569
568 post :bulk_update, :params => {:ids => [1, 5], :time_entry => { :activity_id => 9 }}
570 post :bulk_update, :params => {:ids => [1, 5], :time_entry => { :activity_id => 9 }}
569 assert_response 403
571 assert_response 403
570 end
572 end
571
573
572 def test_bulk_update_with_edit_own_time_entries_permission
574 def test_bulk_update_with_edit_own_time_entries_permission
573 @request.session[:user_id] = 2
575 @request.session[:user_id] = 2
574 Role.find_by_name('Manager').remove_permission! :edit_time_entries
576 Role.find_by_name('Manager').remove_permission! :edit_time_entries
575 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
577 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
576 ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
578 ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
577
579
578 post :bulk_update, :params => {:ids => ids, :time_entry => { :activity_id => 9 }}
580 post :bulk_update, :params => {:ids => ids, :time_entry => { :activity_id => 9 }}
579 assert_response 302
581 assert_response 302
580 end
582 end
581
583
582 def test_bulk_update_with_edit_own_time_entries_permissions_should_be_denied_for_time_entries_of_other_user
584 def test_bulk_update_with_edit_own_time_entries_permissions_should_be_denied_for_time_entries_of_other_user
583 @request.session[:user_id] = 2
585 @request.session[:user_id] = 2
584 Role.find_by_name('Manager').remove_permission! :edit_time_entries
586 Role.find_by_name('Manager').remove_permission! :edit_time_entries
585 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
587 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
586
588
587 post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :activity_id => 9 }}
589 post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :activity_id => 9 }}
588 assert_response 403
590 assert_response 403
589 end
591 end
590
592
591 def test_bulk_update_custom_field
593 def test_bulk_update_custom_field
592 @request.session[:user_id] = 2
594 @request.session[:user_id] = 2
593 post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :custom_field_values => {'10' => '0'} }}
595 post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :custom_field_values => {'10' => '0'} }}
594
596
595 assert_response 302
597 assert_response 302
596 assert_equal ["0", "0"], TimeEntry.where(:id => [1, 2]).collect {|i| i.custom_value_for(10).value}
598 assert_equal ["0", "0"], TimeEntry.where(:id => [1, 2]).collect {|i| i.custom_value_for(10).value}
597 end
599 end
598
600
599 def test_bulk_update_clear_custom_field
601 def test_bulk_update_clear_custom_field
600 field = TimeEntryCustomField.generate!(:field_format => 'string')
602 field = TimeEntryCustomField.generate!(:field_format => 'string')
601 @request.session[:user_id] = 2
603 @request.session[:user_id] = 2
602 post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :custom_field_values => {field.id.to_s => '__none__'} }}
604 post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :custom_field_values => {field.id.to_s => '__none__'} }}
603
605
604 assert_response 302
606 assert_response 302
605 assert_equal ["", ""], TimeEntry.where(:id => [1, 2]).collect {|i| i.custom_value_for(field).value}
607 assert_equal ["", ""], TimeEntry.where(:id => [1, 2]).collect {|i| i.custom_value_for(field).value}
606 end
608 end
607
609
608 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
610 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
609 @request.session[:user_id] = 2
611 @request.session[:user_id] = 2
610 post :bulk_update, :params => {:ids => [1,2], :back_url => '/time_entries'}
612 post :bulk_update, :params => {:ids => [1,2], :back_url => '/time_entries'}
611
613
612 assert_response :redirect
614 assert_response :redirect
613 assert_redirected_to '/time_entries'
615 assert_redirected_to '/time_entries'
614 end
616 end
615
617
616 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
618 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
617 @request.session[:user_id] = 2
619 @request.session[:user_id] = 2
618 post :bulk_update, :params => {:ids => [1,2], :back_url => 'http://google.com'}
620 post :bulk_update, :params => {:ids => [1,2], :back_url => 'http://google.com'}
619
621
620 assert_response :redirect
622 assert_response :redirect
621 assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => Project.find(1).identifier
623 assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => Project.find(1).identifier
622 end
624 end
623
625
624 def test_post_bulk_update_without_edit_permission_should_be_denied
626 def test_post_bulk_update_without_edit_permission_should_be_denied
625 @request.session[:user_id] = 2
627 @request.session[:user_id] = 2
626 Role.find_by_name('Manager').remove_permission! :edit_time_entries
628 Role.find_by_name('Manager').remove_permission! :edit_time_entries
627
629
628 post :bulk_update, :params => {:ids => [1,2]}
630 post :bulk_update, :params => {:ids => [1,2]}
629 assert_response 403
631 assert_response 403
630 end
632 end
631
633
632 def test_destroy
634 def test_destroy
633 @request.session[:user_id] = 2
635 @request.session[:user_id] = 2
634
636
635 delete :destroy, :params => {:id => 1}
637 delete :destroy, :params => {:id => 1}
636 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
638 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
637 assert_equal I18n.t(:notice_successful_delete), flash[:notice]
639 assert_equal I18n.t(:notice_successful_delete), flash[:notice]
638 assert_nil TimeEntry.find_by_id(1)
640 assert_nil TimeEntry.find_by_id(1)
639 end
641 end
640
642
641 def test_destroy_should_fail
643 def test_destroy_should_fail
642 # simulate that this fails (e.g. due to a plugin), see #5700
644 # simulate that this fails (e.g. due to a plugin), see #5700
643 TimeEntry.any_instance.expects(:destroy).returns(false)
645 TimeEntry.any_instance.expects(:destroy).returns(false)
644 @request.session[:user_id] = 2
646 @request.session[:user_id] = 2
645
647
646 delete :destroy, :params => {:id => 1}
648 delete :destroy, :params => {:id => 1}
647 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
649 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
648 assert_equal I18n.t(:notice_unable_delete_time_entry), flash[:error]
650 assert_equal I18n.t(:notice_unable_delete_time_entry), flash[:error]
649 assert_not_nil TimeEntry.find_by_id(1)
651 assert_not_nil TimeEntry.find_by_id(1)
650 end
652 end
651
653
652 def test_index_all_projects
654 def test_index_all_projects
653 get :index
655 get :index
654 assert_response :success
656 assert_response :success
655
657
656 assert_select '.total-for-hours', :text => 'Hours: 162.90'
658 assert_select '.total-for-hours', :text => 'Hours: 162.90'
657 assert_select 'form#query_form[action=?]', '/time_entries'
659 assert_select 'form#query_form[action=?]', '/time_entries'
658 end
660 end
659
661
660 def test_index_all_projects_should_show_log_time_link
662 def test_index_all_projects_should_show_log_time_link
661 @request.session[:user_id] = 2
663 @request.session[:user_id] = 2
662 get :index
664 get :index
663 assert_response :success
665 assert_response :success
664
666
665 assert_select 'a[href=?]', '/time_entries/new', :text => /Log time/
667 assert_select 'a[href=?]', '/time_entries/new', :text => /Log time/
666 end
668 end
667
669
668 def test_index_my_spent_time
670 def test_index_my_spent_time
669 @request.session[:user_id] = 2
671 @request.session[:user_id] = 2
670 get :index, :params => {:user_id => 'me', :c => ['user']}
672 get :index, :params => {:user_id => 'me', :c => ['user']}
671 assert_response :success
673 assert_response :success
672
674
673 users = css_select('table.time-entries tbody td.user').map(&:text).uniq
675 users = css_select('table.time-entries tbody td.user').map(&:text).uniq
674 assert_equal ["John Smith"], users
676 assert_equal ["John Smith"], users
675 end
677 end
676
678
677 def test_index_at_project_level
679 def test_index_at_project_level
678 get :index, :params => {:project_id => 'ecookbook', :c => ['project']}
680 get :index, :params => {:project_id => 'ecookbook', :c => ['project']}
679 assert_response :success
681 assert_response :success
680
682
681 assert_select 'tr.time-entry', 4
683 assert_select 'tr.time-entry', 4
682
684
683 # project and subproject
685 # project and subproject
684 projects = css_select('table.time-entries tbody td.project').map(&:text).uniq.sort
686 projects = css_select('table.time-entries tbody td.project').map(&:text).uniq.sort
685 assert_equal ["eCookbook", "eCookbook Subproject 1"], projects
687 assert_equal ["eCookbook", "eCookbook Subproject 1"], projects
686
688
687 assert_select '.total-for-hours', :text => 'Hours: 162.90'
689 assert_select '.total-for-hours', :text => 'Hours: 162.90'
688 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
690 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
689 end
691 end
690
692
691 def test_index_with_display_subprojects_issues_to_false_should_not_include_subproject_entries
693 def test_index_with_display_subprojects_issues_to_false_should_not_include_subproject_entries
692 entry = TimeEntry.generate!(:project => Project.find(3))
694 entry = TimeEntry.generate!(:project => Project.find(3))
693
695
694 with_settings :display_subprojects_issues => '0' do
696 with_settings :display_subprojects_issues => '0' do
695 get :index, :params => {:project_id => 'ecookbook', :c => ['project']}
697 get :index, :params => {:project_id => 'ecookbook', :c => ['project']}
696 assert_response :success
698 assert_response :success
697
699
698 projects = css_select('table.time-entries tbody td.project').map(&:text).uniq.sort
700 projects = css_select('table.time-entries tbody td.project').map(&:text).uniq.sort
699 assert_equal ["eCookbook"], projects
701 assert_equal ["eCookbook"], projects
700 end
702 end
701 end
703 end
702
704
703 def test_index_with_display_subprojects_issues_to_false_and_subproject_filter_should_include_subproject_entries
705 def test_index_with_display_subprojects_issues_to_false_and_subproject_filter_should_include_subproject_entries
704 entry = TimeEntry.generate!(:project => Project.find(3))
706 entry = TimeEntry.generate!(:project => Project.find(3))
705
707
706 with_settings :display_subprojects_issues => '0' do
708 with_settings :display_subprojects_issues => '0' do
707 get :index, :params => {:project_id => 'ecookbook', :c => ['project'], :subproject_id => 3}
709 get :index, :params => {:project_id => 'ecookbook', :c => ['project'], :subproject_id => 3}
708 assert_response :success
710 assert_response :success
709
711
710 projects = css_select('table.time-entries tbody td.project').map(&:text).uniq.sort
712 projects = css_select('table.time-entries tbody td.project').map(&:text).uniq.sort
711 assert_equal ["eCookbook", "eCookbook Subproject 1"], projects
713 assert_equal ["eCookbook", "eCookbook Subproject 1"], projects
712 end
714 end
713 end
715 end
714
716
715 def test_index_at_project_level_with_issue_id_short_filter
717 def test_index_at_project_level_with_issue_id_short_filter
716 issue = Issue.generate!(:project_id => 1)
718 issue = Issue.generate!(:project_id => 1)
717 TimeEntry.generate!(:issue => issue, :hours => 4)
719 TimeEntry.generate!(:issue => issue, :hours => 4)
718 TimeEntry.generate!(:issue => issue, :hours => 3)
720 TimeEntry.generate!(:issue => issue, :hours => 3)
719 @request.session[:user_id] = 2
721 @request.session[:user_id] = 2
720
722
721 get :index, :params => {:project_id => 'ecookbook', :issue_id => issue.id.to_s, :set_filter => 1}
723 get :index, :params => {:project_id => 'ecookbook', :issue_id => issue.id.to_s, :set_filter => 1}
722 assert_select '.total-for-hours', :text => 'Hours: 7.00'
724 assert_select '.total-for-hours', :text => 'Hours: 7.00'
723 end
725 end
724
726
725 def test_index_at_project_level_with_issue_fixed_version_id_short_filter
727 def test_index_at_project_level_with_issue_fixed_version_id_short_filter
726 version = Version.generate!(:project_id => 1)
728 version = Version.generate!(:project_id => 1)
727 issue = Issue.generate!(:project_id => 1, :fixed_version => version)
729 issue = Issue.generate!(:project_id => 1, :fixed_version => version)
728 TimeEntry.generate!(:issue => issue, :hours => 2)
730 TimeEntry.generate!(:issue => issue, :hours => 2)
729 TimeEntry.generate!(:issue => issue, :hours => 3)
731 TimeEntry.generate!(:issue => issue, :hours => 3)
730 @request.session[:user_id] = 2
732 @request.session[:user_id] = 2
731
733
732 get :index, :params => {:project_id => 'ecookbook', :"issue.fixed_version_id" => version.id.to_s, :set_filter => 1}
734 get :index, :params => {:project_id => 'ecookbook', :"issue.fixed_version_id" => version.id.to_s, :set_filter => 1}
733 assert_select '.total-for-hours', :text => 'Hours: 5.00'
735 assert_select '.total-for-hours', :text => 'Hours: 5.00'
734 end
736 end
735
737
736 def test_index_at_project_level_with_date_range
738 def test_index_at_project_level_with_date_range
737 get :index, :params => {
739 get :index, :params => {
738 :project_id => 'ecookbook',
740 :project_id => 'ecookbook',
739 :f => ['spent_on'],
741 :f => ['spent_on'],
740 :op => {'spent_on' => '><'},
742 :op => {'spent_on' => '><'},
741 :v => {'spent_on' => ['2007-03-20', '2007-04-30']}
743 :v => {'spent_on' => ['2007-03-20', '2007-04-30']}
742 }
744 }
743 assert_response :success
745 assert_response :success
744
746
745 assert_select 'tr.time-entry', 3
747 assert_select 'tr.time-entry', 3
746 assert_select '.total-for-hours', :text => 'Hours: 12.90'
748 assert_select '.total-for-hours', :text => 'Hours: 12.90'
747 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
749 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
748 end
750 end
749
751
750 def test_index_at_project_level_with_date_range_using_from_and_to_params
752 def test_index_at_project_level_with_date_range_using_from_and_to_params
751 get :index, :params => {
753 get :index, :params => {
752 :project_id => 'ecookbook',
754 :project_id => 'ecookbook',
753 :from => '2007-03-20',
755 :from => '2007-03-20',
754 :to => '2007-04-30'
756 :to => '2007-04-30'
755 }
757 }
756 assert_response :success
758 assert_response :success
757
759
758 assert_select 'tr.time-entry', 3
760 assert_select 'tr.time-entry', 3
759 assert_select '.total-for-hours', :text => 'Hours: 12.90'
761 assert_select '.total-for-hours', :text => 'Hours: 12.90'
760 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
762 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
761 end
763 end
762
764
763 def test_index_at_project_level_with_period
765 def test_index_at_project_level_with_period
764 get :index, :params => {
766 get :index, :params => {
765 :project_id => 'ecookbook',
767 :project_id => 'ecookbook',
766 :f => ['spent_on'],
768 :f => ['spent_on'],
767 :op => {'spent_on' => '>t-'},
769 :op => {'spent_on' => '>t-'},
768 :v => {'spent_on' => ['7']}
770 :v => {'spent_on' => ['7']}
769 }
771 }
770 assert_response :success
772 assert_response :success
771
773
772 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
774 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
773 end
775 end
774
776
775 def test_index_should_sort_by_spent_on_and_created_on
777 def test_index_should_sort_by_spent_on_and_created_on
776 t1 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:00:00', :activity_id => 10)
778 t1 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:00:00', :activity_id => 10)
777 t2 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:05:00', :activity_id => 10)
779 t2 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:05:00', :activity_id => 10)
778 t3 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-15', :created_on => '2012-06-16 20:10:00', :activity_id => 10)
780 t3 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-15', :created_on => '2012-06-16 20:10:00', :activity_id => 10)
779
781
780 get :index, :params => {
782 get :index, :params => {
781 :project_id => 1,
783 :project_id => 1,
782 :f => ['spent_on'],
784 :f => ['spent_on'],
783 :op => {'spent_on' => '><'},
785 :op => {'spent_on' => '><'},
784 :v => {'spent_on' => ['2012-06-15', '2012-06-16']}
786 :v => {'spent_on' => ['2012-06-15', '2012-06-16']}
785 }
787 }
786 assert_response :success
788 assert_response :success
787 assert_equal [t2, t1, t3].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
789 assert_equal [t2, t1, t3].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
788
790
789 get :index, :params => {
791 get :index, :params => {
790 :project_id => 1,
792 :project_id => 1,
791 :f => ['spent_on'],
793 :f => ['spent_on'],
792 :op => {'spent_on' => '><'},
794 :op => {'spent_on' => '><'},
793 :v => {'spent_on' => ['2012-06-15', '2012-06-16']},
795 :v => {'spent_on' => ['2012-06-15', '2012-06-16']},
794 :sort => 'spent_on'
796 :sort => 'spent_on'
795 }
797 }
796 assert_response :success
798 assert_response :success
797 assert_equal [t3, t1, t2].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
799 assert_equal [t3, t1, t2].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
798 end
800 end
799
801
800 def test_index_with_issue_status_filter
802 def test_index_with_issue_status_filter
801 Issue.where(:status_id => 4).update_all(:status_id => 2)
803 Issue.where(:status_id => 4).update_all(:status_id => 2)
802 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 4)
804 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 4)
803 entry = TimeEntry.generate!(:issue => issue, :hours => 4.5)
805 entry = TimeEntry.generate!(:issue => issue, :hours => 4.5)
804
806
805 get :index, :params => {
807 get :index, :params => {
806 :f => ['issue.status_id'],
808 :f => ['issue.status_id'],
807 :op => {'issue.status_id' => '='},
809 :op => {'issue.status_id' => '='},
808 :v => {'issue.status_id' => ['4']}
810 :v => {'issue.status_id' => ['4']}
809 }
811 }
810 assert_response :success
812 assert_response :success
811 assert_equal [entry].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
813 assert_equal [entry].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
812 end
814 end
813
815
814 def test_index_with_issue_status_column
816 def test_index_with_issue_status_column
815 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 4)
817 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 4)
816 entry = TimeEntry.generate!(:issue => issue)
818 entry = TimeEntry.generate!(:issue => issue)
817
819
818 get :index, :params => {
820 get :index, :params => {
819 :c => %w(project spent_on issue comments hours issue.status)
821 :c => %w(project spent_on issue comments hours issue.status)
820 }
822 }
821 assert_response :success
823 assert_response :success
822 assert_select 'td.issue-status', :text => issue.status.name
824 assert_select 'td.issue-status', :text => issue.status.name
823 end
825 end
824
826
825 def test_index_with_issue_status_sort
827 def test_index_with_issue_status_sort
826 TimeEntry.delete_all
828 TimeEntry.delete_all
827 TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 1))
829 TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 1))
828 TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 5))
830 TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 5))
829 TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 3))
831 TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 3))
830 TimeEntry.generate!(:project_id => 1)
832 TimeEntry.generate!(:project_id => 1)
831
833
832 get :index, :params => {
834 get :index, :params => {
833 :c => ["hours", 'issue.status'],
835 :c => ["hours", 'issue.status'],
834 :sort => 'issue.status'
836 :sort => 'issue.status'
835 }
837 }
836 assert_response :success
838 assert_response :success
837
839
838 # Make sure that values are properly sorted
840 # Make sure that values are properly sorted
839 values = css_select("td.issue-status").map(&:text).reject(&:blank?)
841 values = css_select("td.issue-status").map(&:text).reject(&:blank?)
840 assert_equal IssueStatus.where(:id => [1, 5, 3]).sorted.pluck(:name), values
842 assert_equal IssueStatus.where(:id => [1, 5, 3]).sorted.pluck(:name), values
841 end
843 end
842
844
843 def test_index_with_issue_tracker_filter
845 def test_index_with_issue_tracker_filter
844 Issue.where(:tracker_id => 2).update_all(:tracker_id => 1)
846 Issue.where(:tracker_id => 2).update_all(:tracker_id => 1)
845 issue = Issue.generate!(:project_id => 1, :tracker_id => 2)
847 issue = Issue.generate!(:project_id => 1, :tracker_id => 2)
846 entry = TimeEntry.generate!(:issue => issue, :hours => 4.5)
848 entry = TimeEntry.generate!(:issue => issue, :hours => 4.5)
847
849
848 get :index, :params => {
850 get :index, :params => {
849 :f => ['issue.tracker_id'],
851 :f => ['issue.tracker_id'],
850 :op => {'issue.tracker_id' => '='},
852 :op => {'issue.tracker_id' => '='},
851 :v => {'issue.tracker_id' => ['2']}
853 :v => {'issue.tracker_id' => ['2']}
852 }
854 }
853 assert_response :success
855 assert_response :success
854 assert_equal [entry].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
856 assert_equal [entry].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
855 end
857 end
856
858
857 def test_index_with_issue_tracker_column
859 def test_index_with_issue_tracker_column
858 issue = Issue.generate!(:project_id => 1, :tracker_id => 2)
860 issue = Issue.generate!(:project_id => 1, :tracker_id => 2)
859 entry = TimeEntry.generate!(:issue => issue)
861 entry = TimeEntry.generate!(:issue => issue)
860
862
861 get :index, :params => {
863 get :index, :params => {
862 :c => %w(project spent_on issue comments hours issue.tracker)
864 :c => %w(project spent_on issue comments hours issue.tracker)
863 }
865 }
864 assert_response :success
866 assert_response :success
865 assert_select 'td.issue-tracker', :text => issue.tracker.name
867 assert_select 'td.issue-tracker', :text => issue.tracker.name
866 end
868 end
867
869
868 def test_index_with_issue_tracker_sort
870 def test_index_with_issue_tracker_sort
869 TimeEntry.delete_all
871 TimeEntry.delete_all
870 TimeEntry.generate!(:issue => Issue.generate!(:tracker_id => 1))
872 TimeEntry.generate!(:issue => Issue.generate!(:tracker_id => 1))
871 TimeEntry.generate!(:issue => Issue.generate!(:tracker_id => 3))
873 TimeEntry.generate!(:issue => Issue.generate!(:tracker_id => 3))
872 TimeEntry.generate!(:issue => Issue.generate!(:tracker_id => 2))
874 TimeEntry.generate!(:issue => Issue.generate!(:tracker_id => 2))
873 TimeEntry.generate!(:project_id => 1)
875 TimeEntry.generate!(:project_id => 1)
874
876
875 get :index, :params => {
877 get :index, :params => {
876 :c => ["hours", 'issue.tracker'],
878 :c => ["hours", 'issue.tracker'],
877 :sort => 'issue.tracker'
879 :sort => 'issue.tracker'
878 }
880 }
879 assert_response :success
881 assert_response :success
880
882
881 # Make sure that values are properly sorted
883 # Make sure that values are properly sorted
882 values = css_select("td.issue-tracker").map(&:text).reject(&:blank?)
884 values = css_select("td.issue-tracker").map(&:text).reject(&:blank?)
883 assert_equal Tracker.where(:id => [1, 2, 3]).sorted.pluck(:name), values
885 assert_equal Tracker.where(:id => [1, 2, 3]).sorted.pluck(:name), values
884 end
886 end
885
887
886 def test_index_with_filter_on_issue_custom_field
888 def test_index_with_filter_on_issue_custom_field
887 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
889 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
888 entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
890 entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
889
891
890 get :index, :params => {
892 get :index, :params => {
891 :f => ['issue.cf_2'],
893 :f => ['issue.cf_2'],
892 :op => {'issue.cf_2' => '='},
894 :op => {'issue.cf_2' => '='},
893 :v => {'issue.cf_2' => ['filter_on_issue_custom_field']}
895 :v => {'issue.cf_2' => ['filter_on_issue_custom_field']}
894 }
896 }
895 assert_response :success
897 assert_response :success
896 assert_equal [entry].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
898 assert_equal [entry].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
897 end
899 end
898
900
899 def test_index_with_issue_custom_field_column
901 def test_index_with_issue_custom_field_column
900 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
902 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
901 entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
903 entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
902
904
903 get :index, :params => {
905 get :index, :params => {
904 :c => %w(project spent_on issue comments hours issue.cf_2)
906 :c => %w(project spent_on issue comments hours issue.cf_2)
905 }
907 }
906 assert_response :success
908 assert_response :success
907 assert_select 'td.issue_cf_2', :text => 'filter_on_issue_custom_field'
909 assert_select 'td.issue_cf_2', :text => 'filter_on_issue_custom_field'
908 end
910 end
909
911
910 def test_index_with_time_entry_custom_field_column
912 def test_index_with_time_entry_custom_field_column
911 field = TimeEntryCustomField.generate!(:field_format => 'string')
913 field = TimeEntryCustomField.generate!(:field_format => 'string')
912 entry = TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value'})
914 entry = TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value'})
913 field_name = "cf_#{field.id}"
915 field_name = "cf_#{field.id}"
914
916
915 get :index, :params => {
917 get :index, :params => {
916 :c => ["hours", field_name]
918 :c => ["hours", field_name]
917 }
919 }
918 assert_response :success
920 assert_response :success
919 assert_select "td.#{field_name}", :text => 'CF Value'
921 assert_select "td.#{field_name}", :text => 'CF Value'
920 end
922 end
921
923
922 def test_index_with_time_entry_custom_field_sorting
924 def test_index_with_time_entry_custom_field_sorting
923 field = TimeEntryCustomField.generate!(:field_format => 'string', :name => 'String Field')
925 field = TimeEntryCustomField.generate!(:field_format => 'string', :name => 'String Field')
924 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 1'})
926 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 1'})
925 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 3'})
927 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 3'})
926 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 2'})
928 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 2'})
927 field_name = "cf_#{field.id}"
929 field_name = "cf_#{field.id}"
928
930
929 get :index, :params => {
931 get :index, :params => {
930 :c => ["hours", field_name],
932 :c => ["hours", field_name],
931 :sort => field_name
933 :sort => field_name
932 }
934 }
933 assert_response :success
935 assert_response :success
934 assert_select "th a.sort", :text => 'String Field'
936 assert_select "th a.sort", :text => 'String Field'
935
937
936 # Make sure that values are properly sorted
938 # Make sure that values are properly sorted
937 values = css_select("td.#{field_name}").map(&:text).reject(&:blank?)
939 values = css_select("td.#{field_name}").map(&:text).reject(&:blank?)
938 assert_equal values.sort, values
940 assert_equal values.sort, values
939 assert_equal 3, values.size
941 assert_equal 3, values.size
940 end
942 end
941
943
942 def test_index_with_query
944 def test_index_with_query
943 query = TimeEntryQuery.new(:project_id => 1, :name => 'Time Entry Query', :visibility => 2)
945 query = TimeEntryQuery.new(:project_id => 1, :name => 'Time Entry Query', :visibility => 2)
944 query.save!
946 query.save!
945 @request.session[:user_id] = 2
947 @request.session[:user_id] = 2
946
948
947 get :index, :params => {:project_id => 'ecookbook', :query_id => query.id}
949 get :index, :params => {:project_id => 'ecookbook', :query_id => query.id}
948 assert_response :success
950 assert_response :success
949 assert_select 'h2', :text => query.name
951 assert_select 'h2', :text => query.name
950 assert_select '#sidebar a.selected', :text => query.name
952 assert_select '#sidebar a.selected', :text => query.name
951 end
953 end
952
954
953 def test_index_atom_feed
955 def test_index_atom_feed
954 get :index, :params => {:project_id => 1, :format => 'atom'}
956 get :index, :params => {:project_id => 1, :format => 'atom'}
955 assert_response :success
957 assert_response :success
956 assert_equal 'application/atom+xml', @response.content_type
958 assert_equal 'application/atom+xml', @response.content_type
957 assert_select 'entry > title', :text => /7\.65 hours/
959 assert_select 'entry > title', :text => /7\.65 hours/
958 end
960 end
959
961
960 def test_index_at_project_level_should_include_csv_export_dialog
962 def test_index_at_project_level_should_include_csv_export_dialog
961 get :index, :params => {
963 get :index, :params => {
962 :project_id => 'ecookbook',
964 :project_id => 'ecookbook',
963 :f => ['spent_on'],
965 :f => ['spent_on'],
964 :op => {'spent_on' => '>='},
966 :op => {'spent_on' => '>='},
965 :v => {'spent_on' => ['2007-04-01']},
967 :v => {'spent_on' => ['2007-04-01']},
966 :c => ['spent_on', 'user']
968 :c => ['spent_on', 'user']
967 }
969 }
968 assert_response :success
970 assert_response :success
969
971
970 assert_select '#csv-export-options' do
972 assert_select '#csv-export-options' do
971 assert_select 'form[action=?][method=get]', '/projects/ecookbook/time_entries.csv' do
973 assert_select 'form[action=?][method=get]', '/projects/ecookbook/time_entries.csv' do
972 # filter
974 # filter
973 assert_select 'input[name=?][value=?]', 'f[]', 'spent_on'
975 assert_select 'input[name=?][value=?]', 'f[]', 'spent_on'
974 assert_select 'input[name=?][value=?]', 'op[spent_on]', '>='
976 assert_select 'input[name=?][value=?]', 'op[spent_on]', '>='
975 assert_select 'input[name=?][value=?]', 'v[spent_on][]', '2007-04-01'
977 assert_select 'input[name=?][value=?]', 'v[spent_on][]', '2007-04-01'
976 # columns
978 # columns
977 assert_select 'input[name=?][value=?]', 'c[]', 'spent_on'
979 assert_select 'input[name=?][value=?]', 'c[]', 'spent_on'
978 assert_select 'input[name=?][value=?]', 'c[]', 'user'
980 assert_select 'input[name=?][value=?]', 'c[]', 'user'
979 assert_select 'input[name=?]', 'c[]', 2
981 assert_select 'input[name=?]', 'c[]', 2
980 end
982 end
981 end
983 end
982 end
984 end
983
985
984 def test_index_cross_project_should_include_csv_export_dialog
986 def test_index_cross_project_should_include_csv_export_dialog
985 get :index
987 get :index
986 assert_response :success
988 assert_response :success
987
989
988 assert_select '#csv-export-options' do
990 assert_select '#csv-export-options' do
989 assert_select 'form[action=?][method=get]', '/time_entries.csv'
991 assert_select 'form[action=?][method=get]', '/time_entries.csv'
990 end
992 end
991 end
993 end
992
994
993 def test_index_csv_all_projects
995 def test_index_csv_all_projects
994 with_settings :date_format => '%m/%d/%Y' do
996 with_settings :date_format => '%m/%d/%Y' do
995 get :index, :params => {:format => 'csv'}
997 get :index, :params => {:format => 'csv'}
996 assert_response :success
998 assert_response :success
997 assert_equal 'text/csv; header=present', response.content_type
999 assert_equal 'text/csv; header=present', response.content_type
998 end
1000 end
999 end
1001 end
1000
1002
1001 def test_index_csv
1003 def test_index_csv
1002 with_settings :date_format => '%m/%d/%Y' do
1004 with_settings :date_format => '%m/%d/%Y' do
1003 get :index, :params => {:project_id => 1, :format => 'csv'}
1005 get :index, :params => {:project_id => 1, :format => 'csv'}
1004 assert_response :success
1006 assert_response :success
1005 assert_equal 'text/csv; header=present', response.content_type
1007 assert_equal 'text/csv; header=present', response.content_type
1006 end
1008 end
1007 end
1009 end
1008
1010
1009 def test_index_csv_should_fill_issue_column_with_tracker_id_and_subject
1011 def test_index_csv_should_fill_issue_column_with_tracker_id_and_subject
1010 issue = Issue.find(1)
1012 issue = Issue.find(1)
1011 entry = TimeEntry.generate!(:issue => issue, :comments => "Issue column content test")
1013 entry = TimeEntry.generate!(:issue => issue, :comments => "Issue column content test")
1012
1014
1013 get :index, :params => {:format => 'csv'}
1015 get :index, :params => {:format => 'csv'}
1014 line = response.body.split("\n").detect {|l| l.include?(entry.comments)}
1016 line = response.body.split("\n").detect {|l| l.include?(entry.comments)}
1015 assert_not_nil line
1017 assert_not_nil line
1016 assert_include "#{issue.tracker} #1: #{issue.subject}", line
1018 assert_include "#{issue.tracker} #1: #{issue.subject}", line
1017 end
1019 end
1018 end
1020 end
@@ -1,60 +1,61
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingTimelogsTest < Redmine::RoutingTest
20 class RoutingTimelogsTest < Redmine::RoutingTest
21 def test_timelogs_global
21 def test_timelogs_global
22 should_route 'GET /time_entries' => 'timelog#index'
22 should_route 'GET /time_entries' => 'timelog#index'
23 should_route 'GET /time_entries.csv' => 'timelog#index', :format => 'csv'
23 should_route 'GET /time_entries.csv' => 'timelog#index', :format => 'csv'
24 should_route 'GET /time_entries.atom' => 'timelog#index', :format => 'atom'
24 should_route 'GET /time_entries.atom' => 'timelog#index', :format => 'atom'
25 should_route 'GET /time_entries/new' => 'timelog#new'
25 should_route 'GET /time_entries/new' => 'timelog#new'
26 should_route 'POST /time_entries/new' => 'timelog#new'
26 should_route 'POST /time_entries/new' => 'timelog#new'
27 should_route 'POST /time_entries' => 'timelog#create'
27 should_route 'POST /time_entries' => 'timelog#create'
28
28
29 should_route 'GET /time_entries/22/edit' => 'timelog#edit', :id => '22'
29 should_route 'GET /time_entries/22/edit' => 'timelog#edit', :id => '22'
30 should_route 'PUT /time_entries/22' => 'timelog#update', :id => '22'
30 should_route 'PATCH /time_entries/22/edit' => 'timelog#edit', :id => '22'
31 should_route 'PATCH /time_entries/22' => 'timelog#update', :id => '22'
31 should_route 'DELETE /time_entries/22' => 'timelog#destroy', :id => '22'
32 should_route 'DELETE /time_entries/22' => 'timelog#destroy', :id => '22'
32 end
33 end
33
34
34 def test_timelogs_scoped_under_project
35 def test_timelogs_scoped_under_project
35 should_route 'GET /projects/foo/time_entries' => 'timelog#index', :project_id => 'foo'
36 should_route 'GET /projects/foo/time_entries' => 'timelog#index', :project_id => 'foo'
36 should_route 'GET /projects/foo/time_entries.csv' => 'timelog#index', :project_id => 'foo', :format => 'csv'
37 should_route 'GET /projects/foo/time_entries.csv' => 'timelog#index', :project_id => 'foo', :format => 'csv'
37 should_route 'GET /projects/foo/time_entries.atom' => 'timelog#index', :project_id => 'foo', :format => 'atom'
38 should_route 'GET /projects/foo/time_entries.atom' => 'timelog#index', :project_id => 'foo', :format => 'atom'
38 should_route 'GET /projects/foo/time_entries/new' => 'timelog#new', :project_id => 'foo'
39 should_route 'GET /projects/foo/time_entries/new' => 'timelog#new', :project_id => 'foo'
39 should_route 'POST /projects/foo/time_entries' => 'timelog#create', :project_id => 'foo'
40 should_route 'POST /projects/foo/time_entries' => 'timelog#create', :project_id => 'foo'
40 end
41 end
41
42
42 def test_timelogs_scoped_under_issues
43 def test_timelogs_scoped_under_issues
43 should_route 'GET /issues/234/time_entries/new' => 'timelog#new', :issue_id => '234'
44 should_route 'GET /issues/234/time_entries/new' => 'timelog#new', :issue_id => '234'
44 should_route 'POST /issues/234/time_entries' => 'timelog#create', :issue_id => '234'
45 should_route 'POST /issues/234/time_entries' => 'timelog#create', :issue_id => '234'
45 end
46 end
46
47
47 def test_timelogs_report
48 def test_timelogs_report
48 should_route 'GET /time_entries/report' => 'timelog#report'
49 should_route 'GET /time_entries/report' => 'timelog#report'
49 should_route 'GET /time_entries/report.csv' => 'timelog#report', :format => 'csv'
50 should_route 'GET /time_entries/report.csv' => 'timelog#report', :format => 'csv'
50
51
51 should_route 'GET /projects/foo/time_entries/report' => 'timelog#report', :project_id => 'foo'
52 should_route 'GET /projects/foo/time_entries/report' => 'timelog#report', :project_id => 'foo'
52 should_route 'GET /projects/foo/time_entries/report.csv' => 'timelog#report', :project_id => 'foo', :format => 'csv'
53 should_route 'GET /projects/foo/time_entries/report.csv' => 'timelog#report', :project_id => 'foo', :format => 'csv'
53 end
54 end
54
55
55 def test_timelogs_bulk_edit
56 def test_timelogs_bulk_edit
56 should_route 'GET /time_entries/bulk_edit' => 'timelog#bulk_edit'
57 should_route 'GET /time_entries/bulk_edit' => 'timelog#bulk_edit'
57 should_route 'POST /time_entries/bulk_update' => 'timelog#bulk_update'
58 should_route 'POST /time_entries/bulk_update' => 'timelog#bulk_update'
58 should_route 'DELETE /time_entries/destroy' => 'timelog#destroy'
59 should_route 'DELETE /time_entries/destroy' => 'timelog#destroy'
59 end
60 end
60 end
61 end
General Comments 0
You need to be logged in to leave comments. Login now