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/Application.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

332 lines
20 KiB
Text

<cfsetting showdebugoutput="false">
<cfsetting enablecfoutputonly="true">
<!---
Payfrit API Application.cfm (updated 2026-01-22)
FIX: Provide a DEFAULT datasource so endpoints can call queryExecute()
without specifying { datasource="payfrit" } every time.
Token-auth gate for /api endpoints.
Public allowlist (NO auth):
- /api/login.cfm
- /api/logout.cfm
- /api/auth/login.cfm
- /api/auth/logout.cfm
- /api/businesses/list.cfm
- /api/servicepoints/list.cfm
Authenticated requests should send:
- Header: X-User-Token: <token from /api/auth/login.cfm>
- Header: X-Business-ID: <selected BusinessID> (required for most endpoints)
--->
<!--- OPTION A: default datasource for the whole app (THIS fixes "missing datasource") --->
<cfapplication
name="payfrit_api"
sessionmanagement="true"
clientmanagement="false"
setclientcookies="false"
datasource="payfrit"
showdebugoutput="false"
>
<!--- Preserve struct key casing in JSON serialization (Flutter expects mixed-case keys) --->
<cfset getApplicationSettings().serialization.preserveCaseForStructKey = true>
<!--- Magic OTP bypass for App Store review (set to true to enable 123456 as universal OTP) --->
<cfset application.MAGIC_OTP_ENABLED = false>
<cfset application.MAGIC_OTP_CODE = "123456">
<!--- Initialize Twilio for SMS --->
<cfif NOT structKeyExists(application, "twilioObj")>
<cftry>
<cfset application.twilioObj = new library.cfc.twilio() />
<cfcatch type="any">
<!--- Twilio component not available, skip initialization --->
</cfcatch>
</cftry>
</cfif>
<!--- Stripe Configuration (loads from config/stripe.cfm) --->
<cfinclude template="config/stripe.cfm">
<!--- Environment Configuration (dev vs prod settings) --->
<cfinclude template="config/environment.cfm">
<cfscript>
function apiAbort(payload) {
writeOutput(serializeJSON(payload));
abort;
}
function headerValue(name) {
// Use servlet request object to get headers (CGI scope doesn't expose custom HTTP headers in Lucee)
try {
req = getPageContext().getRequest();
val = req.getHeader(arguments.name);
if (!isNull(val)) return trim(val);
} catch (any e) {
// Fall back to CGI scope
k = "HTTP_" & ucase(reReplace(arguments.name, "[^A-Za-z0-9]", "_", "all"));
if (structKeyExists(cgi, k)) return trim(cgi[k]);
}
return "";
}
// Determine request path
request._api_scriptName = "";
if (structKeyExists(cgi, "SCRIPT_NAME")) {
request._api_scriptName = cgi.SCRIPT_NAME;
} else if (structKeyExists(cgi, "PATH_INFO")) {
request._api_scriptName = cgi.PATH_INFO;
}
request._api_path = lcase(request._api_scriptName);
// Public allowlist
request._api_isPublic = false;
if (len(request._api_path)) {
if (findNoCase("/api/login.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/logout.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/auth/login.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/auth/logout.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/auth/avatar.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/auth/sendOTP.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/auth/verifyOTP.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/auth/loginOTP.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/auth/verifyLoginOTP.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/auth/completeProfile.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/businesses/list.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/businesses/get.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/businesses/getChildren.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/businesses/update.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/businesses/updateHours.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/servicepoints/list.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/servicepoints/get.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/servicepoints/save.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/servicepoints/delete.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/servicepoints/reassign_all.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/beacons/list.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/beacons/get.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/beacons/save.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/beacons/delete.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/beacons/list_all.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/beacons/getBusinessFromBeacon.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/beacons/reassign_all.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/beacons/lookup.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/assignments/list.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/assignments/save.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/assignments/delete.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/menu/items.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/menu/clearAllData.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/menu/clearOrders.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/addresses/states.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/addresses/debug.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/addresses/list.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/addresses/add.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/addresses/delete.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/addresses/setDefault.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/debug/", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/dev/", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/orders/getOrCreateCart.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/orders/getCart.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/orders/setLineItem.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/orders/submit.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/orders/listForKDS.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/orders/updateStatus.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/orders/checkStatusUpdate.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/orders/getDetail.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/users/search.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/listPending.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/accept.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/listMine.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/complete.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/completeChat.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/getDetails.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/callserver", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/createChat.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/expirestalechats.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/listCategories.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/saveCategory.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/deleteCategory.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/seedCategories.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/listAllTypes.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/listTypes.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/saveType.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/deleteType.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/reorderTypes.cfm", request._api_path)) request._api_isPublic = true;
// Chat endpoints
if (findNoCase("/api/chat/getMessages.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/chat/sendMessage.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/chat/markRead.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/chat/getActiveChat.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/chat/closechat.cfm", request._api_path)) request._api_isPublic = true;
// Token validation (for WebSocket server)
if (findNoCase("/api/auth/validateToken.cfm", request._api_path)) request._api_isPublic = true;
// Worker app endpoints
if (findNoCase("/api/workers/myBusinesses.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/workers/tierStatus.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/workers/createAccount.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/workers/onboardingLink.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/workers/earlyUnlock.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/workers/ledger.cfm", request._api_path)) request._api_isPublic = true;
// Portal endpoints
if (findNoCase("/api/portal/stats.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/portal/myBusinesses.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/portal/team.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/portal/searchUser.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/portal/addTeamMember.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/portal/reassign_employees.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/businesses/setHiring.cfm", request._api_path)) request._api_isPublic = true;
// Order history (auth handled in endpoint)
if (findNoCase("/api/orders/history.cfm", request._api_path)) request._api_isPublic = true;
// User profile (auth handled in endpoint)
if (findNoCase("/api/auth/profile.cfm", request._api_path)) request._api_isPublic = true;
// Menu builder endpoints
if (findNoCase("/api/menu/getForBuilder.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/menu/saveFromBuilder.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/menu/updateStations.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/menu/menus.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/menu/uploadHeader.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/menu/listCategories.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/menu/saveCategory.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/businesses/saveBrandColor.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/tasks/create.cfm", request._api_path)) request._api_isPublic = true;
// Debug endpoints
if (findNoCase("/api/debug/checkToken.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/debug/headers.cfm", request._api_path)) request._api_isPublic = true;
// Admin endpoints (protected by localhost check in each file)
if (findNoCase("/api/admin/resetTestData.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/debugTasks.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/testTaskType.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/testTaskInsert.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/debugBusinesses.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/setupStations.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/setupModifierTemplates.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/migrateModifierTemplates.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/deleteOrphanModifiers.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/fixShakeFlavors.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/eliminateCategories.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/cleanupCategories.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/deleteOrphans.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/switchBeacons.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/randomizePrices.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/debugTemplateLinks.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/fixBigDeansCategories.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/migrateToCategories.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/addItemCategoryColumn.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/checkBigDeans.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/updateBigDeans.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/debugBigDeansMenu.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/listTables.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/describeTable.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/setupBigDeansInfo.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/beaconStatus.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/updateBeaconMapping.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/setupBigDeansStations.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/copyDrinksToBigDeans.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/debugDrinkStructure.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/addDrinkModifiers.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/add_task_columns.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/add_service_category.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/createChatMessagesTable.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/addTaskSourceColumns.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/debugChatMessages.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/cleanupDuplicateEmployees.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/debugEmployees.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/debugUserByPhone.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/admin/setEmployeeActive.cfm", request._api_path)) request._api_isPublic = true;
// Setup/Import endpoints
if (findNoCase("/api/setup/importBusiness.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/setup/analyzeMenu.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/setup/analyzeMenuImages.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/setup/saveWizard.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/setup/downloadImages.cfm", request._api_path)) request._api_isPublic = true;
// Stations endpoints
if (findNoCase("/api/stations/list.cfm", request._api_path)) request._api_isPublic = true;
// Ratings endpoints (setup + token-based submission)
if (findNoCase("/api/ratings/setup.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/ratings/submit.cfm", request._api_path)) request._api_isPublic = true;
// App info endpoints (public, no auth needed)
if (findNoCase("/api/app/about.cfm", request._api_path)) request._api_isPublic = true;
// Stripe endpoints
if (findNoCase("/api/stripe/onboard.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/stripe/status.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/stripe/createPaymentIntent.cfm", request._api_path)) request._api_isPublic = true;
if (findNoCase("/api/stripe/webhook.cfm", request._api_path)) request._api_isPublic = true;
}
// Carry session values into request (if present)
if (!structKeyExists(request, "UserID") && structKeyExists(session, "UserID")) {
request.UserID = Duplicate(session.UserID);
}
if (!structKeyExists(request, "BusinessID") && structKeyExists(session, "BusinessID")) {
request.BusinessID = Duplicate(session.BusinessID);
}
// Token auth: X-User-Token -> request.UserID
request._api_userToken = headerValue("X-User-Token");
if (len(request._api_userToken)) {
try {
request._api_qTok = queryExecute(
"SELECT UserID FROM UserTokens WHERE Token = ? LIMIT 1",
[ { value = request._api_userToken, cfsqltype = "cf_sql_varchar" } ],
{ datasource = "payfrit" }
);
if (request._api_qTok.recordCount EQ 1) {
request.UserID = request._api_qTok.UserID;
session.UserID = request._api_qTok.UserID;
}
} catch (any e) {
// ignore; treated as unauthenticated
}
}
// Business header: X-Business-ID -> request.BusinessID
request._api_hdrBiz = headerValue("X-Business-ID");
if (len(request._api_hdrBiz) && isNumeric(request._api_hdrBiz)) {
request.BusinessID = int(request._api_hdrBiz);
session.BusinessID = request.BusinessID;
}
// Enforce auth (except public)
if (!request._api_isPublic) {
if (!structKeyExists(request, "UserID") || !isNumeric(request.UserID) || request.UserID LTE 0) {
apiAbort({
"OK": false,
"ERROR": "not_logged_in",
"DEBUG_PATH": request._api_path,
"DEBUG_IS_PUBLIC": request._api_isPublic,
"DEBUG_SCRIPT_NAME": structKeyExists(cgi, "SCRIPT_NAME") ? cgi.SCRIPT_NAME : "N/A",
"DEBUG_PATH_INFO": structKeyExists(cgi, "PATH_INFO") ? cgi.PATH_INFO : "N/A",
"DEBUG_HAS_TOKEN": len(request._api_userToken) > 0,
"DEBUG_TOKEN_PREFIX": len(request._api_userToken) > 8 ? left(request._api_userToken, 8) : request._api_userToken
});
}
if (!structKeyExists(request, "BusinessID") || !isNumeric(request.BusinessID) || request.BusinessID LTE 0) {
apiAbort({ "OK": false, "ERROR": "no_business_selected" });
}
}
</cfscript>