Skip to content

Commit a6f5d21

Browse files
committed
Prevent overwriting completed manager scores
1 parent 5f76c67 commit a6f5d21

3 files changed

Lines changed: 75 additions & 9 deletions

File tree

app/controllers/staff/mark_scores_controller.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ def show
5858

5959
def update
6060
manager = authorize(policy_scope(User).find(params[:id]), :mark_scores?)
61-
need_update_evaluations = policy_scope(EvaluationUserCapability).where(id: save_params[:mark_score].collect { |ms| ms[:id_euc] })
61+
need_update_evaluations = policy_scope(EvaluationUserCapability)
62+
.where(id: save_params[:mark_score].collect { |ms| ms[:id_euc] })
63+
.where(form_status: "self_assessment_done")
6264
need_update_evaluations.each do |euc|
6365
p = save_params[:mark_score].find { |ms| ms[:id_euc] == euc.id }.to_h
6466
update_h = p.select { |key, value| !key.start_with?("p_") && value != "none" && key != "id_cet" && key != "id_euc" && key != "id_user" }
@@ -104,7 +106,9 @@ def update
104106

105107
def score_confirm
106108
authorize(policy_scope(User).find(params[:id]), :score_confirm?)
107-
evaluation_user_capabilities = policy_scope(EvaluationUserCapability).where(id: params[:euc_ids])
109+
evaluation_user_capabilities = policy_scope(EvaluationUserCapability)
110+
.where(id: params[:euc_ids])
111+
.where(form_status: "self_assessment_done")
108112
evaluation_user_capabilities.each do |evaluation_user_capability|
109113
evaluation_user_capability.update_form_status_to("manager_scored", current_user)
110114
evaluation_user_capability.update_columns(

app/javascript/react/modal_dialog/MarkScoreConfirmDialog.jsx

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import {scoreConfirmPath} from "../utils/url";
55

66
export function MarkScoreConfirmDialog({accepted, message, euc_ids, onClose}) {
77
const modalRef = React.useRef();
8+
const submittingRef = React.useRef(false);
9+
const [submitting, setSubmitting] = React.useState(false);
810
React.useEffect(() => {
911
const modal = new coreui.Modal('#coreuiModal');
1012
modal.show();
@@ -15,13 +17,19 @@ export function MarkScoreConfirmDialog({accepted, message, euc_ids, onClose}) {
1517

1618
const handleConfirm = (event) => {
1719
event.preventDefault();
20+
if (submittingRef.current) return;
21+
22+
submittingRef.current = true;
23+
setSubmitting(true);
1824
put(scoreConfirmPath(userId()), {body: {euc_ids}}).then((response) => {
19-
if (response.ok) {
20-
const result_json = response.json;
21-
result_json.then(result => {
22-
window.location.href = result.go_path;
23-
});
24-
}
25+
if (!response.ok) throw new Error("Failed to confirm mark scores");
26+
27+
return response.json;
28+
}).then(result => {
29+
window.location.href = result.go_path;
30+
}).catch(() => {
31+
submittingRef.current = false;
32+
setSubmitting(false);
2533
});
2634
}
2735

@@ -36,7 +44,7 @@ export function MarkScoreConfirmDialog({accepted, message, euc_ids, onClose}) {
3644
{message}
3745
</div>
3846
<div className="modal-footer">
39-
{accepted ? <button onClick={handleConfirm} className="btn btn-primary">{reviewLabels().submit}</button> : null}
47+
{accepted ? <button onClick={handleConfirm} className="btn btn-primary" disabled={submitting}>{reviewLabels().submit}</button> : null}
4048
<button className="btn btn-secondary" type="button" data-coreui-dismiss="modal">{reviewLabels().close}</button>
4149
</div>
4250
</div>

test/controllers/staff/mark_scores_controller_test.rb

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,33 @@ class Staff::MarkScoresControllerTest < ActionDispatch::IntegrationTest
137137
assert_equal [4], response_body.fetch("need_review_evaluations").pluck("mark_score_group").uniq
138138
end
139139

140+
test "save does not overwrite a review after manager scoring is complete" do
141+
euc = evaluation_user_capabilities(:euc_supervisor_high)
142+
euc.update!(
143+
form_status: "manager_scored",
144+
work_quality: 3,
145+
work_load: 3,
146+
work_attitude: 3
147+
)
148+
149+
put staff_mark_score_path(@manager, format: :json), params: {
150+
company_evaluation_ids: [company_evaluations(:ce_one).id],
151+
group_level: "supervisor",
152+
mark_score_group: "4",
153+
mark_score: [{
154+
id_user: euc.user_id,
155+
id_cet: euc.company_evaluation_template_id,
156+
id_euc: euc.id,
157+
work_quality: 0,
158+
work_load: 0,
159+
work_attitude: 0
160+
}]
161+
}, as: :json
162+
163+
assert_response :success
164+
assert_equal [3, 3, 3], euc.reload.values_at(:work_quality, :work_load, :work_attitude).map(&:to_i)
165+
end
166+
140167
test "score confirm returns mark scores path when reviews remain" do
141168
euc = evaluation_user_capabilities(:euc_supervisor_high)
142169
company_evaluation_ids = [company_evaluations(:ce_one).id]
@@ -168,4 +195,31 @@ class Staff::MarkScoresControllerTest < ActionDispatch::IntegrationTest
168195
assert_response :success
169196
assert_equal staff_root_path, JSON.parse(response.body).fetch("go_path")
170197
end
198+
199+
test "score confirm is idempotent after manager scoring is complete" do
200+
euc = evaluation_user_capabilities(:euc_supervisor_high)
201+
company_evaluation_ids = [company_evaluations(:ce_one).id]
202+
203+
put score_confirm_staff_mark_score_path(@manager, format: :json), params: {
204+
euc_ids: [euc.id],
205+
company_evaluation_ids: company_evaluation_ids
206+
}, as: :json
207+
208+
assert_response :success
209+
assert_equal 1, euc.euc_form_status_histories.where(
210+
previous_form_status: "self_assessment_done",
211+
form_status: "manager_scored"
212+
).count
213+
214+
put score_confirm_staff_mark_score_path(@manager, format: :json), params: {
215+
euc_ids: [euc.id],
216+
company_evaluation_ids: company_evaluation_ids
217+
}, as: :json
218+
219+
assert_response :success
220+
assert_equal 1, euc.euc_form_status_histories.where(
221+
previous_form_status: "self_assessment_done",
222+
form_status: "manager_scored"
223+
).count
224+
end
171225
end

0 commit comments

Comments
 (0)