Feature #13596 » 0001-Adds-setting-to-allow-timelog-on-closed-issues.patch
app/controllers/context_menus_controller.rb | ||
---|---|---|
33 | 33 | |
34 | 34 |
@can = { |
35 | 35 |
:edit => @issues.all?(&:attributes_editable?), |
36 |
:log_time => (@project && User.current.allowed_to?(:log_time, @project)),
|
|
36 |
:log_time => @issue&.time_loggable?,
|
|
37 | 37 |
:copy => User.current.allowed_to?(:copy_issues, @projects) && Issue.allowed_target_projects.any?, |
38 | 38 |
:add_watchers => User.current.allowed_to?(:add_issue_watchers, @projects), |
39 | 39 |
:delete => @issues.all?(&:deletable?), |
app/models/issue.rb | ||
---|---|---|
188 | 188 |
end |
189 | 189 |
end |
190 | 190 | |
191 |
# Returns true if user or current user is allowed to log time on the issue |
|
192 |
def time_loggable?(user=User.current) |
|
193 |
user.allowed_to?(:log_time, project) && (!Setting.timelog_accept_future_dates? || !closed?) |
|
194 |
end |
|
195 | ||
191 | 196 |
# Returns true if user or current user is allowed to edit or add notes to the issue |
192 | 197 |
def editable?(user=User.current) |
193 | 198 |
attributes_editable?(user) || notes_addable?(user) |
app/models/time_entry.rb | ||
---|---|---|
182 | 182 |
if spent_on && spent_on_changed? && user |
183 | 183 |
errors.add :base, I18n.t(:error_spent_on_future_date) if !Setting.timelog_accept_future_dates? && (spent_on > user.today) |
184 | 184 |
end |
185 |
if !Setting.timelog_accept_closed_issues? && issue&.closed? && issue&.was_closed? |
|
186 |
errors.add :base, I18n.t(:error_spent_on_closed_issue) |
|
187 |
end |
|
185 | 188 |
end |
186 | 189 | |
187 | 190 |
def hours=(h) |
app/views/issues/_action_menu.html.erb | ||
---|---|---|
3 | 3 |
:onclick => 'showAndScrollTo("update", "issue_notes"); return false;', |
4 | 4 |
:class => 'icon icon-edit ', :accesskey => accesskey(:edit) if @issue.editable? %> |
5 | 5 |
<%= link_to sprite_icon('time-add', l(:button_log_time)), new_issue_time_entry_path(@issue), |
6 |
:class => 'icon icon-time-add ' if User.current.allowed_to?(:log_time, @project) %>
|
|
6 |
:class => 'icon icon-time-add ' if @issue.time_loggable? %>
|
|
7 | 7 |
<%= watcher_link(@issue, User.current) %> |
8 | 8 |
<%= link_to sprite_icon('copy', l(:button_copy)), project_copy_issue_path(@project, @issue), |
9 | 9 |
:class => 'icon icon-copy ' if User.current.allowed_to?(:copy_issues, @project) && Issue.allowed_target_projects.any? %> |
app/views/issues/_edit.html.erb | ||
---|---|---|
9 | 9 |
</div> |
10 | 10 |
</fieldset> |
11 | 11 |
<% end %> |
12 |
<% if User.current.allowed_to?(:log_time, @issue.project) %>
|
|
12 |
<% if @issue.time_loggable? %>
|
|
13 | 13 |
<fieldset class="tabular" id="log_time"><legend><%= l(:button_log_time) %></legend> |
14 | 14 |
<%= labelled_fields_for :time_entry, @time_entry do |time_entry| %> |
15 | 15 |
<div class="splitcontent"> |
app/views/settings/_timelog.html.erb | ||
---|---|---|
9 | 9 |
<p><%= setting_check_box :timelog_accept_0_hours %></p> |
10 | 10 | |
11 | 11 |
<p><%= setting_check_box :timelog_accept_future_dates %></p> |
12 | ||
13 |
<p><%= setting_check_box :timelog_accept_closed_issues %></p> |
|
12 | 14 |
</div> |
13 | 15 | |
14 | 16 |
<fieldset class="box"> |
config/locales/en.yml | ||
---|---|---|
235 | 235 |
error_exceeds_maximum_hours_per_day: "Cannot log more than %{max_hours} hours on the same day (%{logged_hours} hours have already been logged)" |
236 | 236 |
error_can_not_delete_auth_source: "This authentication mode is in use and cannot be deleted." |
237 | 237 |
error_spent_on_future_date: "Cannot log time on a future date" |
238 |
error_spent_on_closed_issue: "Cannot log time on a closed issue" |
|
238 | 239 |
error_not_allowed_to_log_time_for_other_users: "You are not allowed to log time for other users" |
239 | 240 |
error_can_not_execute_macro_html: "Error executing the <strong>%{name}</strong> macro (%{error})" |
240 | 241 |
error_macro_does_not_accept_block: "This macro does not accept a block of text" |
... | ... | |
519 | 520 |
setting_timelog_accept_0_hours: Accept time logs with 0 hours |
520 | 521 |
setting_timelog_max_hours_per_day: Maximum hours that can be logged per day and user |
521 | 522 |
setting_timelog_accept_future_dates: Accept time logs on future dates |
523 |
setting_timelog_accept_closed_issues: Accept time logs on closed issues |
|
522 | 524 |
setting_show_status_changes_in_mail_subject: Show status changes in issue mail notifications subject |
523 | 525 |
setting_project_list_defaults: Projects list defaults |
524 | 526 |
setting_twofa: Two-factor authentication |
config/settings.yml | ||
---|---|---|
347 | 347 |
default: 999 |
348 | 348 |
timelog_accept_future_dates: |
349 | 349 |
default: 1 |
350 |
timelog_accept_closed_issues: |
|
351 |
default: 1 |
|
350 | 352 |
show_status_changes_in_mail_subject: |
351 | 353 |
default: 1 |
352 | 354 |
wiki_tablesort_enabled: |
test/functional/issues_controller_test.rb | ||
---|---|---|
5885 | 5885 |
assert_select 'input[name=?]', 'time_entry[hours]', 0 |
5886 | 5886 |
end |
5887 | 5887 | |
5888 |
def test_get_edit_should_not_display_the_time_entry_form_on_closed_issue |
|
5889 |
with_settings :timelog_accept_closed_issues => '0' do |
|
5890 |
@request.session[:user_id] = 2 |
|
5891 |
issue = Issue.find(1) |
|
5892 |
issue.update :status => IssueStatus.find(5) |
|
5893 |
get(:edit, :params => {:id => 1}) |
|
5894 |
assert_select 'input[name=?]', 'time_entry[hours]', 0 |
|
5895 |
end |
|
5896 |
end |
|
5897 | ||
5888 | 5898 |
def test_get_edit_with_params |
5889 | 5899 |
@request.session[:user_id] = 2 |
5890 | 5900 |
get( |
... | ... | |
6341 | 6351 |
assert mail.subject.include?("(#{IssueStatus.find(2).name})") |
6342 | 6352 |
end |
6343 | 6353 | |
6354 |
def test_update_should_accept_time_entry_when_closing_issue |
|
6355 |
with_settings :timelog_accept_closed_issues => '0' do |
|
6356 |
issue = Issue.find(1) |
|
6357 |
assert_equal 1, issue.status_id |
|
6358 |
@request.session[:user_id] = 2 |
|
6359 |
assert_difference('TimeEntry.count', 1) do |
|
6360 |
put( |
|
6361 |
:update, |
|
6362 |
:params => { |
|
6363 |
:id => 1, |
|
6364 |
:issue => { |
|
6365 |
:status_id => 5, |
|
6366 |
}, |
|
6367 |
:time_entry => { |
|
6368 |
:hours => '2', |
|
6369 |
:comments => '', |
|
6370 |
:activity_id => TimeEntryActivity.first |
|
6371 |
} |
|
6372 |
} |
|
6373 |
) |
|
6374 |
end |
|
6375 |
assert_redirected_to :action => 'show', :id => '1' |
|
6376 |
issue.reload |
|
6377 |
assert issue.closed? |
|
6378 |
end |
|
6379 |
end |
|
6380 | ||
6381 |
def test_update_should_not_accept_time_entry_on_closed_issue |
|
6382 |
with_settings :timelog_accept_closed_issues => '0' do |
|
6383 |
issue = Issue.find(1) |
|
6384 |
issue.update :status => IssueStatus.find(5) |
|
6385 |
@request.session[:user_id] = 2 |
|
6386 |
assert_no_difference('TimeEntry.count') do |
|
6387 |
put( |
|
6388 |
:update, |
|
6389 |
:params => { |
|
6390 |
:id => 1, |
|
6391 |
:issue => { |
|
6392 |
}, |
|
6393 |
:time_entry => { |
|
6394 |
:hours => '2', |
|
6395 |
:comments => '', |
|
6396 |
:activity_id => TimeEntryActivity.first |
|
6397 |
} |
|
6398 |
} |
|
6399 |
) |
|
6400 |
end |
|
6401 |
assert_response :success |
|
6402 |
end |
|
6403 |
end |
|
6404 | ||
6344 | 6405 |
def test_put_update_with_note_only |
6345 | 6406 |
notes = 'Note added by IssuesControllerTest#test_update_with_note_only' |
6346 | 6407 |
test/unit/time_entry_test.rb | ||
---|---|---|
175 | 175 |
end |
176 | 176 |
end |
177 | 177 | |
178 |
def test_should_not_accept_closed_issue |
|
179 |
with_settings :timelog_accept_closed_issues => '0' do |
|
180 |
project = Project.find(1) |
|
181 |
entry = TimeEntry.generate project: project |
|
182 |
issue = project.issues.to_a.detect(&:closed?) |
|
183 |
entry.issue = issue |
|
184 |
assert !entry.save |
|
185 |
assert entry.errors[:base].present? |
|
186 |
assert_equal 'Cannot log time on a closed issue', entry.errors[:base].first |
|
187 |
end |
|
188 |
end |
|
189 | ||
178 | 190 |
def test_should_require_spent_on |
179 | 191 |
with_settings :timelog_accept_future_dates => '0' do |
180 | 192 |
entry = TimeEntry.find(1) |
- « Previous
- 1
- 2
- Next »