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 1210249f54 Normalize database column and table names across entire codebase
Update all SQL queries, query result references, and ColdFusion code to match
the renamed database schema. Tables use plural CamelCase, PKs are all `ID`,
column prefixes stripped (e.g. BusinessName→Name, UserFirstName→FirstName).

Key changes:
- Strip table-name prefixes from all column references (Businesses, Users,
  Addresses, Hours, Menus, Categories, Items, Stations, Orders,
  OrderLineItems, Tasks, TaskCategories, TaskRatings, QuickTaskTemplates,
  ScheduledTaskDefinitions, ChatMessages, Beacons, ServicePoints, Employees,
  VisitorTrackings, ApiPerfLogs, tt_States, tt_Days, tt_AddressTypes,
  tt_OrderTypes, tt_TaskTypes)
- Rename PK references from {TableName}ID to ID in all queries
- Rewrite 7 admin beacon files to use ServicePoints.BeaconID instead of
  dropped lt_Beacon_Businesses_ServicePoints link table
- Rewrite beacon assignment files (list, save, delete) for new schema
- Fix FK references incorrectly changed to ID (OrderLineItems.OrderID,
  Categories.MenuID, Tasks.CategoryID, ServicePoints.BeaconID)
- Update Addresses: AddressLat→Latitude, AddressLng→Longitude
- Update Users: UserPassword→Password, UserIsEmailVerified→IsEmailVerified,
  UserIsActive→IsActive, UserBalance→Balance, etc.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 15:39:12 -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 UserID = :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>