fix: feedback token race condition (FOR UPDATE), generic error for public users
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Project CI / Lint & Validate (pull_request) Successful in 6s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 6s
Universal: PR Check / Validate PR (pull_request) Failing after 4s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Universal: Workflow Sync Trigger / Sync workflows to live repos (pull_request) Failing after 2s
Universal: Auto Version Bump / Version Bump (push) Successful in 7s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 7s
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Universal: Build & Release / Build & Release Pipeline (pull_request) Successful in 16s
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Project CI / Lint & Validate (pull_request) Successful in 6s
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 6s
Universal: PR Check / Validate PR (pull_request) Failing after 4s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Universal: Workflow Sync Trigger / Sync workflows to live repos (pull_request) Failing after 2s
Universal: Auto Version Bump / Version Bump (push) Successful in 7s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 7s
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Universal: Build & Release / Build & Release Pipeline (pull_request) Successful in 16s
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
This commit is contained in:
@@ -51,16 +51,7 @@ class CustomerFeedbackHelper
|
||||
{
|
||||
$db = Factory::getContainer()->get(DatabaseInterface::class);
|
||||
|
||||
$db->setQuery($db->getQuery(true)
|
||||
->select('id, wo_id, contact_id, status')
|
||||
->from('#__mokosuitefield_feedback_requests')
|
||||
->where($db->quoteName('token') . ' = ' . $db->quote($token)));
|
||||
$request = $db->loadObject();
|
||||
|
||||
if (!$request) return (object) ['success' => false, 'error' => 'Invalid feedback link'];
|
||||
if ($request->status === 'completed') return (object) ['success' => false, 'error' => 'Feedback already submitted'];
|
||||
|
||||
// Validate inputs
|
||||
// Validate inputs before DB access
|
||||
$rating = max(1, min(5, $rating));
|
||||
$npsScore = max(0, min(10, $npsScore));
|
||||
|
||||
@@ -69,7 +60,20 @@ class CustomerFeedbackHelper
|
||||
|
||||
$db->transactionStart();
|
||||
try {
|
||||
// Record feedback
|
||||
// Lock the request row to prevent race condition on token reuse
|
||||
$db->setQuery('SELECT id, wo_id, contact_id, status FROM #__mokosuitefield_feedback_requests WHERE '
|
||||
. $db->quoteName('token') . ' = ' . $db->quote($token) . ' FOR UPDATE');
|
||||
$request = $db->loadObject();
|
||||
|
||||
if (!$request) {
|
||||
$db->transactionRollback();
|
||||
return (object) ['success' => false, 'error' => 'Invalid feedback link'];
|
||||
}
|
||||
if ($request->status === 'completed') {
|
||||
$db->transactionRollback();
|
||||
return (object) ['success' => false, 'error' => 'Feedback already submitted'];
|
||||
}
|
||||
|
||||
$feedback = (object) [
|
||||
'request_id' => $request->id,
|
||||
'wo_id' => $request->wo_id,
|
||||
@@ -81,7 +85,6 @@ class CustomerFeedbackHelper
|
||||
];
|
||||
$db->insertObject('#__mokosuitefield_feedback', $feedback);
|
||||
|
||||
// Mark request as completed
|
||||
$db->setQuery($db->getQuery(true)
|
||||
->update('#__mokosuitefield_feedback_requests')
|
||||
->set($db->quoteName('status') . ' = ' . $db->quote('completed'))
|
||||
@@ -91,7 +94,8 @@ class CustomerFeedbackHelper
|
||||
$db->transactionCommit();
|
||||
} catch (\Throwable $e) {
|
||||
$db->transactionRollback();
|
||||
return (object) ['success' => false, 'error' => $e->getMessage()];
|
||||
// Don't leak internal errors to public users
|
||||
return (object) ['success' => false, 'error' => 'Unable to save feedback. Please try again.'];
|
||||
}
|
||||
|
||||
return (object) ['success' => true, 'rating' => $rating, 'nps' => $npsScore];
|
||||
|
||||
Reference in New Issue
Block a user