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/auth/completeProfile.cfm
John Mizerek bc88f28e60 Fix UserID column references in auth endpoints after schema normalization
Users table primary key was renamed from UserID to ID but these
endpoints still referenced the old column name, causing server_error
on login/signup OTP flow.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 17:15:46 -08:00

147 lines
4.8 KiB
Text

<cfsetting showdebugoutput="false">
<cfsetting enablecfoutputonly="true">
<cfcontent type="application/json; charset=utf-8" reset="true">
<cfheader name="Cache-Control" value="no-store">
<cfscript>
/**
* Complete user profile after phone verification
*
* POST: {
* "firstName": "John",
* "lastName": "Smith",
* "email": "john@example.com"
* }
*
* Requires auth token in header: X-User-Token: <token>
* (Parsed by Application.cfm into request.UserID)
*
* Returns: { OK: true } and sends confirmation email
*/
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 {};
}
function getAuthUserId() {
// Use request.UserID set by Application.cfm from X-User-Token header
if (structKeyExists(request, "UserID") && isNumeric(request.UserID) && request.UserID > 0) {
return request.UserID;
}
return 0;
}
function isValidEmail(required string email) {
return reFind("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$", arguments.email) > 0;
}
try {
userId = getAuthUserId();
if (userId == 0) {
apiAbort({ "OK": false, "ERROR": "unauthorized", "MESSAGE": "Authentication required" });
}
data = readJsonBody();
firstName = structKeyExists(data, "firstName") ? trim(data.firstName) : "";
lastName = structKeyExists(data, "lastName") ? trim(data.lastName) : "";
email = structKeyExists(data, "email") ? trim(lCase(data.email)) : "";
// Validate required fields
if (!len(firstName)) {
apiAbort({ "OK": false, "ERROR": "missing_first_name", "MESSAGE": "First name is required" });
}
if (!len(lastName)) {
apiAbort({ "OK": false, "ERROR": "missing_last_name", "MESSAGE": "Last name is required" });
}
if (!len(email) || !isValidEmail(email)) {
apiAbort({ "OK": false, "ERROR": "invalid_email", "MESSAGE": "Please enter a valid email address" });
}
// Check if email is already used by another verified account
qEmailCheck = queryExecute("
SELECT ID FROM Users
WHERE EmailAddress = :email
AND IsEmailVerified = 1
AND UserID != :userId
LIMIT 1
", {
email: { value: email, cfsqltype: "cf_sql_varchar" },
userId: { value: userId, cfsqltype: "cf_sql_integer" }
}, { datasource: "payfrit" });
if (qEmailCheck.recordCount > 0) {
apiAbort({ "OK": false, "ERROR": "email_exists", "MESSAGE": "This email is already associated with another account" });
}
// Get current user UUID for email confirmation link
qUser = queryExecute("
SELECT UUID FROM Users WHERE ID = :userId
", { userId: { value: userId, cfsqltype: "cf_sql_integer" } }, { datasource: "payfrit" });
// Update user profile AND mark account as verified/active
// This completes the signup process
queryExecute("
UPDATE Users
SET FirstName = :firstName,
LastName = :lastName,
EmailAddress = :email,
IsEmailVerified = 0,
IsContactVerified = 1,
IsActive = 1
WHERE ID = :userId
", {
firstName: { value: firstName, cfsqltype: "cf_sql_varchar" },
lastName: { value: lastName, cfsqltype: "cf_sql_varchar" },
email: { value: email, cfsqltype: "cf_sql_varchar" },
userId: { value: userId, cfsqltype: "cf_sql_integer" }
}, { datasource: "payfrit" });
// Send confirmation email (non-blocking - don't fail if mail fails)
confirmLink = "https://biz.payfrit.com/confirm_email.cfm?UUID=" & qUser.UUID;
emailBody = "
<p>Welcome to Payfrit, #firstName#!</p>
<p>Please click the link below to confirm your email address:</p>
<p><a href='#confirmLink#'>Confirm Email</a></p>
<p>Or copy and paste this URL into your browser:</p>
<p>#confirmLink#</p>
<p>Thanks,<br>The Payfrit Team</p>
";
emailSent = false;
try {
mailService = new mail();
mailService.setTo(email);
mailService.setFrom("admin@payfrit.com");
mailService.setSubject("Welcome to Payfrit - Please confirm your email");
mailService.setType("html");
mailService.send(body=emailBody);
emailSent = true;
} catch (any mailErr) {
// Mail failed but profile was saved - continue
}
writeOutput(serializeJSON({
"OK": true,
"MESSAGE": emailSent ? "Profile updated. Please check your email to confirm your address." : "Profile updated."
}));
} catch (any e) {
apiAbort({
"OK": false,
"ERROR": "server_error",
"MESSAGE": e.message
});
}
</cfscript>