Converts 200+ endpoint files to use queryTimed() wrapper which tracks DB query count and execution time. Restores perf dashboard files that were accidentally moved to _scripts/. Includes portal UI updates.
93 lines
2.7 KiB
Text
93 lines
2.7 KiB
Text
<cfsetting showdebugoutput="false">
|
|
<cfsetting enablecfoutputonly="true">
|
|
<cfcontent type="application/json; charset=utf-8" reset="true">
|
|
|
|
<cfscript>
|
|
// Search users by phone, email, or username
|
|
// Input: Query (search term)
|
|
// Output: { OK: true, USERS: [...] }
|
|
|
|
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();
|
|
query = structKeyExists(data, "Query") ? trim(data.Query) : "";
|
|
currentUserId = val(structKeyExists(data, "CurrentUserID") ? data.CurrentUserID : 0);
|
|
|
|
if (len(query) < 3) {
|
|
apiAbort({ "OK": true, "USERS": [], "MESSAGE": "Query must be at least 3 characters" });
|
|
}
|
|
|
|
// Search by phone, email, or first/last name
|
|
// Exclude the current user from results
|
|
searchTerm = "%" & query & "%";
|
|
|
|
qUsers = queryTimed("
|
|
SELECT
|
|
u.ID,
|
|
u.FirstName,
|
|
u.LastName,
|
|
u.EmailAddress,
|
|
u.ContactNumber,
|
|
u.ImageExtension
|
|
FROM Users u
|
|
WHERE u.ID != :currentUserId
|
|
AND (
|
|
u.ContactNumber LIKE :searchTerm
|
|
OR u.EmailAddress LIKE :searchTerm
|
|
OR u.FirstName LIKE :searchTerm
|
|
OR u.LastName LIKE :searchTerm
|
|
OR CONCAT(u.FirstName, ' ', u.LastName) LIKE :searchTerm
|
|
)
|
|
ORDER BY u.FirstName, u.LastName
|
|
LIMIT 10
|
|
", {
|
|
currentUserId: { value: currentUserId, cfsqltype: "cf_sql_integer" },
|
|
searchTerm: { value: searchTerm, cfsqltype: "cf_sql_varchar" }
|
|
}, { datasource: "payfrit" });
|
|
|
|
users = [];
|
|
for (user in qUsers) {
|
|
// Mask phone number for privacy (show last 4 digits only)
|
|
maskedPhone = "";
|
|
if (len(trim(user.ContactNumber)) >= 4) {
|
|
maskedPhone = "***-***-" & right(user.ContactNumber, 4);
|
|
}
|
|
|
|
arrayAppend(users, {
|
|
"UserID": user.ID,
|
|
"Name": trim(user.FirstName & " " & user.LastName),
|
|
"Email": user.EmailAddress,
|
|
"Phone": maskedPhone,
|
|
"AvatarUrl": len(trim(user.ImageExtension)) ? application.baseUrl & "/uploads/users/" & user.ID & "." & user.ImageExtension : ""
|
|
});
|
|
}
|
|
|
|
apiAbort({
|
|
"OK": true,
|
|
"USERS": users,
|
|
"COUNT": arrayLen(users)
|
|
});
|
|
|
|
} catch (any e) {
|
|
apiAbort({
|
|
"OK": false,
|
|
"ERROR": "server_error",
|
|
"MESSAGE": e.message
|
|
});
|
|
}
|
|
</cfscript>
|