This allows beacons to use any Eddystone-UID configuration where: - Namespace (10 bytes) matches first 20 hex chars of shard UUID - Instance bytes encode Major/Minor for business/service point lookup Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
176 lines
6.4 KiB
Text
176 lines
6.4 KiB
Text
<cfsetting showdebugoutput="false">
|
|
<cfsetting enablecfoutputonly="true">
|
|
<cfcontent type="application/json; charset=utf-8" reset="true">
|
|
|
|
<cftry>
|
|
|
|
<cfset requestData = deserializeJSON(toString(getHttpRequestData().content))>
|
|
|
|
<!--- ============================================================================
|
|
SHARDING FORMAT: { "Beacons": [{ "UUID": "...", "Major": 49, "Minor": 15 }] }
|
|
Resolves via BeaconShards -> Businesses (BeaconMajor) -> ServicePoints (BeaconMinor)
|
|
============================================================================ --->
|
|
<cfif structKeyExists(requestData, "Beacons") AND isArray(requestData.Beacons) AND arrayLen(requestData.Beacons) GT 0>
|
|
<cfset beacons = []>
|
|
|
|
<cfloop array="#requestData.Beacons#" index="beaconData">
|
|
<cfset uuid = "">
|
|
<cfset major = 0>
|
|
<cfset minor = -1>
|
|
|
|
<!--- Extract UUID (normalize: remove dashes, add back in standard format) --->
|
|
<cfif structKeyExists(beaconData, "UUID")>
|
|
<cfset rawUuid = uCase(reReplace(beaconData.UUID, "-", "", "all"))>
|
|
<cfif len(rawUuid) EQ 32>
|
|
<!--- Convert to standard UUID format with dashes for DB lookup --->
|
|
<cfset uuid = lCase(mid(rawUuid,1,8) & "-" & mid(rawUuid,9,4) & "-" & mid(rawUuid,13,4) & "-" & mid(rawUuid,17,4) & "-" & mid(rawUuid,21,12))>
|
|
</cfif>
|
|
</cfif>
|
|
|
|
<cfif structKeyExists(beaconData, "Major") AND isNumeric(beaconData.Major)>
|
|
<cfset major = int(beaconData.Major)>
|
|
</cfif>
|
|
|
|
<cfif structKeyExists(beaconData, "Minor") AND isNumeric(beaconData.Minor)>
|
|
<cfset minor = int(beaconData.Minor)>
|
|
</cfif>
|
|
|
|
<cfif len(uuid) EQ 0 OR major LT 0 OR minor LT 0>
|
|
<cfcontinue>
|
|
</cfif>
|
|
|
|
<!--- Resolve via sharding: Namespace (first 20 chars of UUID) -> Shard -> Business (Major) -> ServicePoint (Minor) --->
|
|
<!--- Extract namespace (first 20 hex chars) from beacon UUID for matching --->
|
|
<cfset namespace = lCase(left(reReplace(uuid, "-", "", "all"), 20))>
|
|
|
|
<cfquery name="qShard" datasource="payfrit">
|
|
SELECT
|
|
biz.ID AS BusinessID,
|
|
biz.Name AS BusinessName,
|
|
biz.ParentBusinessID,
|
|
COALESCE(parent.Name, '') AS ParentBusinessName,
|
|
sp.ID AS ServicePointID,
|
|
sp.Name AS ServicePointName,
|
|
bs.UUID AS ShardUUID,
|
|
(SELECT COUNT(*) FROM Businesses WHERE ParentBusinessID = biz.ID) AS ChildCount
|
|
FROM BeaconShards bs
|
|
JOIN Businesses biz ON biz.BeaconShardID = bs.ID AND biz.BeaconMajor = <cfqueryparam cfsqltype="cf_sql_smallint" value="#major#">
|
|
LEFT JOIN ServicePoints sp ON sp.BusinessID = biz.ID AND sp.BeaconMinor = <cfqueryparam cfsqltype="cf_sql_smallint" value="#minor#"> AND sp.IsActive = 1
|
|
LEFT JOIN Businesses parent ON biz.ParentBusinessID = parent.ID
|
|
WHERE LEFT(REPLACE(bs.UUID, '-', ''), 20) = <cfqueryparam cfsqltype="cf_sql_varchar" value="#namespace#">
|
|
AND bs.IsActive = 1
|
|
AND biz.IsDemo = 0
|
|
AND biz.IsPrivate = 0
|
|
LIMIT 1
|
|
</cfquery>
|
|
|
|
<cfif qShard.recordCount GT 0>
|
|
<cfset arrayAppend(beacons, {
|
|
"UUID" = uCase(reReplace(uuid, "-", "", "all")),
|
|
"Major" = major,
|
|
"Minor" = minor,
|
|
"BeaconID" = 0,
|
|
"BeaconName" = qShard.ServicePointName,
|
|
"BusinessID" = qShard.BusinessID,
|
|
"BusinessName" = qShard.BusinessName,
|
|
"ServicePointID" = val(qShard.ServicePointID),
|
|
"ServicePointName" = qShard.ServicePointName,
|
|
"ParentBusinessID" = val(qShard.ParentBusinessID),
|
|
"ParentBusinessName" = qShard.ParentBusinessName,
|
|
"HasChildren" = qShard.ChildCount GT 0
|
|
})>
|
|
</cfif>
|
|
</cfloop>
|
|
|
|
<cfoutput>#serializeJSON({
|
|
"OK" = true,
|
|
"ERROR" = "",
|
|
"BEACONS" = beacons
|
|
})#</cfoutput>
|
|
<cfabort>
|
|
</cfif>
|
|
|
|
<!--- ============================================================================
|
|
LEGACY FORMAT: { "UUIDs": ["uuid1", "uuid2", ...] }
|
|
Resolves via old Beacons table
|
|
============================================================================ --->
|
|
<cfif NOT structKeyExists(requestData, "UUIDs") OR NOT isArray(requestData.UUIDs) OR arrayLen(requestData.UUIDs) EQ 0>
|
|
<cfoutput>#serializeJSON({
|
|
"OK" = true,
|
|
"ERROR" = "",
|
|
"BEACONS" = []
|
|
})#</cfoutput>
|
|
<cfabort>
|
|
</cfif>
|
|
|
|
<!--- Clean and normalize UUIDs (remove dashes, uppercase) --->
|
|
<cfset cleanUUIDs = []>
|
|
<cfloop array="#requestData.UUIDs#" index="uuid">
|
|
<cfset cleanUUID = uCase(reReplace(uuid, "-", "", "all"))>
|
|
<cfif len(cleanUUID) EQ 32>
|
|
<cfset arrayAppend(cleanUUIDs, cleanUUID)>
|
|
</cfif>
|
|
</cfloop>
|
|
|
|
<cfif arrayLen(cleanUUIDs) EQ 0>
|
|
<cfoutput>#serializeJSON({
|
|
"OK" = true,
|
|
"ERROR" = "",
|
|
"BEACONS" = []
|
|
})#</cfoutput>
|
|
<cfabort>
|
|
</cfif>
|
|
|
|
<!--- Query for matching beacons with business info --->
|
|
<cfquery name="qBeacons" datasource="payfrit">
|
|
SELECT
|
|
b.ID AS BeaconID,
|
|
b.Name AS BeaconName,
|
|
b.UUID,
|
|
COALESCE(sp.ID, 0) AS ServicePointID,
|
|
COALESCE(sp.Name, '') AS ServicePointName,
|
|
COALESCE(sp.BusinessID, lt.BusinessID, b.BusinessID) AS BusinessID,
|
|
biz.Name AS BusinessName,
|
|
biz.ParentBusinessID AS ParentBusinessID,
|
|
COALESCE(parent.Name, '') AS ParentBusinessName,
|
|
(SELECT COUNT(*) FROM Businesses WHERE ParentBusinessID = biz.ID) AS ChildCount
|
|
FROM Beacons b
|
|
LEFT JOIN ServicePoints sp ON sp.BeaconID = b.ID
|
|
LEFT JOIN lt_BeaconsID_BusinessesID lt ON lt.BeaconID = b.ID
|
|
INNER JOIN Businesses biz ON COALESCE(sp.BusinessID, lt.BusinessID, b.BusinessID) = biz.ID
|
|
LEFT JOIN Businesses parent ON biz.ParentBusinessID = parent.ID
|
|
WHERE b.UUID IN (<cfqueryparam value="#arrayToList(cleanUUIDs)#" cfsqltype="cf_sql_varchar" list="true">)
|
|
AND b.IsActive = 1
|
|
AND biz.IsDemo = 0
|
|
AND biz.IsPrivate = 0
|
|
</cfquery>
|
|
|
|
<cfset beacons = []>
|
|
<cfloop query="qBeacons">
|
|
<cfset arrayAppend(beacons, {
|
|
"UUID" = qBeacons.UUID,
|
|
"BeaconID" = qBeacons.BeaconID,
|
|
"BeaconName" = qBeacons.BeaconName,
|
|
"BusinessID" = qBeacons.BusinessID,
|
|
"BusinessName" = qBeacons.BusinessName,
|
|
"ServicePointID" = qBeacons.ServicePointID,
|
|
"ServicePointName" = qBeacons.ServicePointName,
|
|
"ParentBusinessID" = val(qBeacons.ParentBusinessID),
|
|
"ParentBusinessName" = qBeacons.ParentBusinessName,
|
|
"HasChildren" = qBeacons.ChildCount GT 0
|
|
})>
|
|
</cfloop>
|
|
|
|
<cfoutput>#serializeJSON({
|
|
"OK" = true,
|
|
"ERROR" = "",
|
|
"BEACONS" = beacons
|
|
})#</cfoutput>
|
|
|
|
<cfcatch type="any">
|
|
<cfoutput>#serializeJSON({
|
|
"OK" = false,
|
|
"ERROR" = cfcatch.message
|
|
})#</cfoutput>
|
|
</cfcatch>
|
|
</cftry>
|