This repository has been archived on 2026-03-21. You can view files and clone it, but cannot push or open issues or pull requests.
payfrit-biz/api/ratings/submit.cfm
John Mizerek 8f9da2fbf0 Add Manage Menus toolbar button, photo upload, and various improvements
- Move menu manager button to toolbar next to Save Menu for visibility
- Implement server-side photo upload for menu items
- Strip base64 data URLs from save payload to reduce size
- Add scheduled tasks, quick tasks, ratings, and task categories APIs
- Add vertical support and brand color features

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 14:43:41 -08:00

144 lines
6.7 KiB
Text

<cfsetting showdebugoutput="false">
<cfcontent type="application/json; charset=utf-8">
<cfscript>
function readJsonBody() {
var raw = getHttpRequestData().content;
if (isNull(raw) || len(trim(raw)) == 0) return {};
try {
var data = deserializeJSON(raw);
return isStruct(data) ? data : {};
} catch (any e) {
return {};
}
}
try {
data = readJsonBody();
// Token can come from URL param or JSON body
token = "";
if (structKeyExists(url, "token")) token = trim(url.token);
if (len(token) == 0 && structKeyExists(data, "token")) token = trim(data.token);
if (len(token) == 0) {
writeOutput(serializeJSON({ "OK": false, "ERROR": "missing_token", "MESSAGE": "Rating token is required." }));
abort;
}
// Look up the rating by token
qRating = queryExecute("
SELECT r.*, t.TaskTitle,
u_for.UserFirstName AS ForUserFirstName, u_for.UserLastName AS ForUserLastName,
u_by.UserFirstName AS ByUserFirstName, u_by.UserLastName AS ByUserLastName
FROM TaskRatings r
JOIN Tasks t ON t.TaskID = r.TaskRatingTaskID
LEFT JOIN Users u_for ON u_for.UserID = r.TaskRatingForUserID
LEFT JOIN Users u_by ON u_by.UserID = r.TaskRatingByUserID
WHERE r.TaskRatingAccessToken = ?
LIMIT 1
", [{ value = token, cfsqltype = "cf_sql_varchar" }]);
if (qRating.recordCount == 0) {
writeOutput(serializeJSON({ "OK": false, "ERROR": "invalid_token", "MESSAGE": "Rating not found or link is invalid." }));
abort;
}
// Check if expired
if (qRating.TaskRatingExpiresOn < now()) {
writeOutput(serializeJSON({ "OK": false, "ERROR": "expired", "MESSAGE": "This rating link has expired." }));
abort;
}
// Check if already completed
if (len(trim(qRating.TaskRatingCompletedOn)) > 0) {
writeOutput(serializeJSON({ "OK": false, "ERROR": "already_submitted", "MESSAGE": "This rating has already been submitted." }));
abort;
}
// If GET request (or no rating data), return rating info for display
isSubmission = structKeyExists(data, "onTime") || structKeyExists(data, "completedScope")
|| structKeyExists(data, "requiredFollowup") || structKeyExists(data, "continueAllow")
|| structKeyExists(data, "prepared") || structKeyExists(data, "respectful")
|| structKeyExists(data, "wouldAutoAssign");
if (!isSubmission) {
// Return rating details for UI to display
result = {
"OK": true,
"RatingID": qRating.TaskRatingID,
"Direction": qRating.TaskRatingDirection,
"TaskTitle": qRating.TaskTitle,
"ForUserName": trim(qRating.ForUserFirstName & " " & qRating.ForUserLastName),
"ExpiresOn": dateTimeFormat(qRating.TaskRatingExpiresOn, "yyyy-mm-dd HH:nn:ss")
};
// Include appropriate questions based on direction
if (qRating.TaskRatingDirection == "customer_rates_worker" || qRating.TaskRatingDirection == "admin_rates_worker") {
result["Questions"] = {
"onTime": "Was the worker on time?",
"completedScope": "Was the scope completed?",
"requiredFollowup": "Was follow-up required?",
"continueAllow": "Continue to allow these tasks?"
};
} else if (qRating.TaskRatingDirection == "worker_rates_customer") {
result["Questions"] = {
"prepared": "Was the customer prepared?",
"completedScope": "Was the scope clear?",
"respectful": "Was the customer respectful?",
"wouldAutoAssign": "Would you serve this customer again?"
};
}
writeOutput(serializeJSON(result));
abort;
}
// Process submission based on direction
if (qRating.TaskRatingDirection == "customer_rates_worker" || qRating.TaskRatingDirection == "admin_rates_worker") {
queryExecute("
UPDATE TaskRatings SET
TaskRatingOnTime = ?,
TaskRatingCompletedScope = ?,
TaskRatingRequiredFollowup = ?,
TaskRatingContinueAllow = ?,
TaskRatingCompletedOn = NOW()
WHERE TaskRatingID = ?
", [
{ value = structKeyExists(data,"onTime") ? (data.onTime ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"onTime") },
{ value = structKeyExists(data,"completedScope") ? (data.completedScope ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"completedScope") },
{ value = structKeyExists(data,"requiredFollowup") ? (data.requiredFollowup ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"requiredFollowup") },
{ value = structKeyExists(data,"continueAllow") ? (data.continueAllow ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"continueAllow") },
{ value = qRating.TaskRatingID, cfsqltype = "cf_sql_integer" }
]);
} else if (qRating.TaskRatingDirection == "worker_rates_customer") {
queryExecute("
UPDATE TaskRatings SET
TaskRatingPrepared = ?,
TaskRatingCompletedScope = ?,
TaskRatingRespectful = ?,
TaskRatingWouldAutoAssign = ?,
TaskRatingCompletedOn = NOW()
WHERE TaskRatingID = ?
", [
{ value = structKeyExists(data,"prepared") ? (data.prepared ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"prepared") },
{ value = structKeyExists(data,"completedScope") ? (data.completedScope ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"completedScope") },
{ value = structKeyExists(data,"respectful") ? (data.respectful ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"respectful") },
{ value = structKeyExists(data,"wouldAutoAssign") ? (data.wouldAutoAssign ? 1 : 0) : javaCast("null",""), cfsqltype = "cf_sql_tinyint", null = !structKeyExists(data,"wouldAutoAssign") },
{ value = qRating.TaskRatingID, cfsqltype = "cf_sql_integer" }
]);
}
writeOutput(serializeJSON({
"OK": true,
"MESSAGE": "Rating submitted successfully. Thank you for your feedback!"
}));
} catch (any e) {
writeOutput(serializeJSON({
"OK": false,
"ERROR": "server_error",
"MESSAGE": "Error submitting rating",
"DETAIL": e.message
}));
}
</cfscript>