Skip to content

Commit 5a3e02f

Browse files
authored
Handle blank issue inputs (#210)
* Refactor TimeRebalancer and TimerSessionsController to handle blank issue inputs and improve error handling * remove redundant methods and LINT * Replace assigns * Refactor issue selection validation and update handling in timer sessions * LINT & replace `it` due to linter complaining * pass blank as an arg
1 parent a1c28ea commit 5a3e02f

6 files changed

Lines changed: 92 additions & 19 deletions

File tree

app/controllers/timer_sessions_controller.rb

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
class TimerSessionsController < TrackyController
44
def index
55
@timer_sessions_in_range = TimerSession.includes(:time_entries, :timer_session_time_entries, issues: :project)
6-
.finished
7-
.created_by(User.current)
6+
.finished.created_by(User.current)
87
@non_matching_timer_session_ids = TimeDiscrepancyLoader.uneven_timer_session_ids(@timer_sessions_in_range)
98
set_timer_sessions
109
@timer_offset = offset_for_time_zone
@@ -25,10 +24,7 @@ def time_entries_in_range(timer_sessions)
2524

2625
def rebalance
2726
@timer_session = user_scoped_timer_session(params[:id])
28-
TimeRebalancer.new(
29-
@timer_session.relevant_issues.map(&:id),
30-
@timer_session
31-
).force_rebalance
27+
TimeRebalancer.new(@timer_session.relevant_issues.map(&:id), @timer_session).force_rebalance
3228
flash[:notice] = l(:notice_successful_update)
3329
redirect_to timer_sessions_path
3430
end
@@ -55,20 +51,20 @@ def continue
5551
timer_session_template = user_scoped_timer_session(params[:id])
5652
linked_issues = timer_session_template.relevant_issues
5753
new_timer_session = timer_session_template.dup
58-
new_timer_session.update(timer_end: nil,
59-
finished: false,
54+
new_timer_session.update(timer_end: nil, finished: false,
6055
timer_start: (User.current.time_zone || Time.zone).now.asctime)
6156
IssueConnector.new(linked_issues.map(&:id) || [], new_timer_session).run
6257
redirect_to timer_sessions_path
6358
end
6459

6560
def update
6661
@timer_session = user_scoped_timer_session(params[:id])
67-
if @timer_session.update(timer_session_params)
68-
TimeRebalancer.new(timer_session_params[:issue_ids],
69-
@timer_session).rebalance_entries
62+
63+
if @timer_session.update(timer_session_update_params)
64+
TimeRebalancer.new(selected_issue_ids || @timer_session.relevant_issues.map(&:id), @timer_session)
65+
.rebalance_entries
7066
flash[:notice] = l(:notice_successful_update)
71-
render_js(@timer_session.valid? ? :update_redirect : :update)
67+
render_js(:update_redirect)
7268
else
7369
render_js :update
7470
end
@@ -95,11 +91,18 @@ def user_scoped_timer_session(id)
9591
TimerSession.where(user: User.current).find(id)
9692
end
9793

94+
def selected_issue_ids
95+
return timer_session_params[:issue_ids].reject(&:blank?) if timer_session_params.key?(:issue_ids)
96+
97+
Array.wrap(timer_session_params[:issue_id]).reject(&:blank?) if timer_session_params.key?(:issue_id)
98+
end
99+
98100
def timer_session_params
99-
params.require(:timer_session).permit(:comments,
100-
:timer_start,
101-
:timer_end,
102-
issue_ids: [])
101+
params.require(:timer_session).permit(:comments, :timer_start, :timer_end, :issue_id, issue_ids: [])
102+
end
103+
104+
def timer_session_update_params
105+
timer_session_params.except(:issue_id, :issue_ids)
103106
end
104107

105108
def report_query_params

app/models/finished_timer_session_validator.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ def validate_comment_present
3030
end
3131

3232
def validate_issues_selected
33-
@record.errors.add(:issue_id, :no_selection) if @record.issues.none?
33+
@record.errors.add(:issue_id, :no_selection) if @record.issues.blank?
34+
@record.errors.add(:issue_id, :no_selection) if @record.issues.any?(&:blank?)
3435
end
3536

3637
def validate_minimal_duration

app/services/time_rebalancer.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22

33
class TimeRebalancer
44
def initialize(issues, timer_session)
5-
@issues = (issues || []).map(&:to_i)
5+
@issues = Array.wrap(issues).reject(&:blank?).map(&:to_i).uniq
66
@issue_ids = timer_session.relevant_issues.map(&:id).map(&:to_i)
77
@timer_session = timer_session
88
validate
99
end
1010

1111
def rebalance_entries
12+
return if @issues.blank?
1213
return unless @timer_session.valid?
1314

1415
if issues_changed?
@@ -28,6 +29,7 @@ def force_rebalance
2829

2930
def validate
3031
@timer_session.errors.add(:issue_id, :no_selection) if @issues.blank?
32+
@timer_session.errors.add(:issue_id, :no_selection) if @issues.any?(&:blank?)
3133
end
3234

3335
def handle_issues_changed

app/views/timer_sessions/update.js.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<% @timer_session.validate %>
1+
<% @timer_session.validate if @timer_session.errors.empty? %>
22
$('#ajax-modal').html(
33
("<%= j render 'edit_modal', timer_session: @timer_session %>")
44
);

test/functional/timer_sessions_controller_test.rb

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,15 @@ class TimerSessionsControllerTest < ActionController::TestCase
1919

2020
def setup
2121
@issue = Issue.find(1)
22+
@other_issue = Issue.find(2)
2223
@time_entry = TimeEntry.find(1)
2324
@user = User.find(1)
2425
@timer_session = FactoryBot.create(:timer_session,
2526
user: @user)
27+
TimerSessionIssue.create!(
28+
issue: @issue,
29+
timer_session_id: @timer_session.id
30+
)
2631
TimerSessionTimeEntry.create!(
2732
time_entry: @time_entry,
2833
timer_session_id: @timer_session.id
@@ -71,6 +76,58 @@ def setup
7176
assert @timer_session.comments, 'NEW IPA TOPIC'
7277
end
7378

79+
test 'update accepts singular issue_id param' do
80+
put(:update, params: {
81+
id: @timer_session.id,
82+
timer_session: { comments: 'NEW IPA TOPIC', issue_id: @other_issue.id }
83+
}, xhr: true)
84+
85+
timer_session = @controller.instance_variable_get(:@timer_session)
86+
87+
assert_response 200
88+
assert_empty timer_session.errors[:issue_id]
89+
assert_equal [@other_issue.id], @timer_session.reload.issue_ids
90+
end
91+
92+
test 'update with empty string in issue array selection does not continue' do
93+
original_issue_ids = @timer_session.issue_ids
94+
95+
put(:update, params: {
96+
id: @timer_session.id,
97+
timer_session: { comments: 'NEW IPA TOPIC', issue_ids: [''] }
98+
}, xhr: true)
99+
100+
timer_session = @controller.instance_variable_get(:@timer_session)
101+
102+
assert_response 200
103+
assert_includes timer_session.errors[:issue_id],
104+
I18n.t('activerecord.errors.models.timer_session.attributes.issue_id.no_selection', locale: :en)
105+
assert_equal original_issue_ids, @timer_session.reload.issue_ids
106+
end
107+
108+
test 'update with an empty array as issue selection does not continue' do
109+
original_issue_ids = @timer_session.issue_ids
110+
111+
put :update,
112+
params: { id: @timer_session.id },
113+
body: {
114+
timer_session: {
115+
comments: 'NEW IPA TOPIC',
116+
issue_ids: []
117+
}
118+
}.to_json,
119+
as: :json,
120+
format: :js,
121+
xhr: true
122+
123+
timer_session = @controller.instance_variable_get(:@timer_session)
124+
125+
assert_response 200
126+
assert_includes timer_session.errors[:issue_id],
127+
I18n.t('activerecord.errors.models.timer_session.attributes.issue_id.no_selection', locale: :en)
128+
assert_equal original_issue_ids, @timer_session.reload.issue_ids
129+
end
130+
74131
test 'continue' do
75132
start_timer_sessions_count = TimerSession.all.count
76133
post(:continue, params: { id: @timer_session.id })

test/unit/time_rebalancer_test.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,14 @@ class TimeRebalancerTest < ActiveSupport::TestCase
8787
assert_equal 1, TimerSessionIssue.count
8888
assert_equal issue_id, @timer_session.issues.first.id
8989
end
90+
91+
test '#rebalance_entries - blank issue input adds no_selection error' do
92+
original_issue_ids = @timer_session.issue_ids
93+
94+
TimeRebalancer.new([''], @timer_session).rebalance_entries
95+
96+
assert_includes @timer_session.errors[:issue_id],
97+
I18n.t('activerecord.errors.models.timer_session.attributes.issue_id.no_selection', locale: :en)
98+
assert_equal original_issue_ids, @timer_session.reload.issue_ids
99+
end
90100
end

0 commit comments

Comments
 (0)