// Validate a user token (for WebSocket server authentication) // Input: Token // Output: { OK: true, UserID: ..., UserType: 'customer'/'worker' } function apiAbort(required struct payload) { writeOutput(serializeJSON(payload)); abort; } function readJsonBody() { var raw = getHttpRequestData().content; if (isNull(raw)) raw = ""; if (!len(trim(raw))) return {}; try { var data = deserializeJSON(raw); if (isStruct(data)) return data; } catch (any e) {} return {}; } try { data = readJsonBody(); token = trim(structKeyExists(data, "Token") ? data.Token : ""); if (!len(token)) { apiAbort({ "OK": false, "ERROR": "missing_params", "MESSAGE": "Token is required" }); } // Look up the token qToken = queryExecute(" SELECT ut.UserID, u.UserFirstName, u.UserLastName FROM UserTokens ut JOIN Users u ON u.UserID = ut.UserID WHERE ut.Token = :token LIMIT 1 ", { token: { value: token, cfsqltype: "cf_sql_varchar" } }, { datasource: "payfrit" }); if (qToken.recordCount == 0) { apiAbort({ "OK": false, "ERROR": "invalid_token", "MESSAGE": "Token is invalid or expired" }); } userID = qToken.UserID; // Determine if user is a worker (has any active employment) qWorker = queryExecute(" SELECT COUNT(*) as cnt FROM lt_Users_Businesses_Employees WHERE UserID = :userID AND EmployeeIsActive = 1 ", { userID: { value: userID, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" }); userType = qWorker.cnt > 0 ? "worker" : "customer"; apiAbort({ "OK": true, "UserID": userID, "UserType": userType, "UserName": trim(qToken.UserFirstName & " " & qToken.UserLastName) }); } catch (any e) { apiAbort({ "OK": false, "ERROR": "server_error", "MESSAGE": e.message }); }