234 attempt to fix js error Uncaught SyntaxError: Unexpected identifier 'hidden'

This commit is contained in:
2026-04-27 17:57:24 +03:00
parent 8a32a0d5f0
commit 74c073bd7e
149 changed files with 14361 additions and 8886 deletions
+5 -13
View File
@@ -1,15 +1,7 @@
<cfcomponent extends="taffy.core.baseSerializer">
component extends="taffy.core.baseSerializer" {
<!--- remove because causing tests to fail
<cfset variables.anythingToXml = application.anythingToXml />
--->
public function getAsXML() output="false" taffy_mime="application/xml" taffy_default="true" {
return application.anythingToXml.toXml(variables.data);
}
<cffunction
name="getAsXML"
output="false"
taffy:mime="application/xml"
taffy:default="true">
<cfreturn application.anythingToXml.toXml(variables.data) />
</cffunction>
</cfcomponent>
}
+4 -9
View File
@@ -1,11 +1,6 @@
<cfinterface>
interface {
<cffunction name="init" hint="I accept a configuration structure to setup and return myself">
<cfargument name="config" />
<cfargument name="tracker" />
</cffunction>
<cffunction name="saveLog" hint="I log or otherwise notify you of an exception">
<cfargument name="exception" />
</cffunction>
public function init(config, tracker) hint="I accept a configuration structure to setup and return myself";
public function saveLog(exception) hint="I log or otherwise notify you of an exception";
</cfinterface>
}
-553
View File
@@ -1,553 +0,0 @@
<!---
Copyright 2009 Nathan Mische
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--->
<cfcomponent displayname="JSONUtil" output="false">
<cfset this.deserialzeJSON = deserializeFromJSON />
<cfset this.serializeJSON = serializeToJSON />
<cfset this.deserialize = deserializeFromJSON />
<cfset this.serialize = serializeToJSON />
<cffunction name="init" output="false">
<cfreturn this />
</cffunction>
<cffunction
name="deserializeFromJSON"
access="public"
returntype="any"
output="false"
hint="Converts a JSON (JavaScript Object Notation) string data representation into CFML data, such as a CFML structure or array.">
<cfargument
name="JSONVar"
type="string"
required="true"
hint="A string that contains a valid JSON construct, or variable that represents one." />
<cfargument
name="strictMapping"
type="boolean"
required="false"
default="true"
hint="A Boolean value that specifies whether to convert the JSON strictly, as follows:
<ul>
<li><code>true:</code> (Default) Convert the JSON string to ColdFusion data types that correspond directly to the JSON data types.</li>
<li><code>false:</code> Determine if the JSON string contains representations of ColdFusion queries, and if so, convert them to queries.</li>
</ul>" />
<!--- DECLARE VARIABLES --->
<cfset var ar = ArrayNew(1) />
<cfset var st = StructNew() />
<cfset var dataType = "" />
<cfset var inQuotes = false />
<cfset var startPos = 1 />
<cfset var nestingLevel = 0 />
<cfset var dataSize = 0 />
<cfset var i = 1 />
<cfset var skipIncrement = false />
<cfset var j = 0 />
<cfset var char = "" />
<cfset var dataStr = "" />
<cfset var structVal = "" />
<cfset var structKey = "" />
<cfset var colonPos = "" />
<cfset var qRows = 0 />
<cfset var qCols = "" />
<cfset var qCol = "" />
<cfset var qData = "" />
<cfset var curCharIndex = "" />
<cfset var curChar = "" />
<cfset var result = "" />
<cfset var unescapeVals = "\\,\"",\/,\b,\t,\n,\f,\r" />
<cfset var unescapeToVals = "\,"",/,#Chr(8)#,#Chr(9)#,#Chr(10)#,#Chr(12)#,#Chr(13)#" />
<cfset var unescapeVals2 = '\,",/,b,t,n,f,r' />
<cfset var unescapetoVals2 = '\,",/,#Chr(8)#,#Chr(9)#,#Chr(10)#,#Chr(12)#,#Chr(13)#' />
<cfset var dJSONString = "" />
<cfset var _data = Trim(arguments.JSONVar) />
<!--- NUMBER --->
<cfif IsNumeric(_data)>
<cfreturn Val(_data) />
<!--- NULL --->
<cfelseif _data EQ "null">
<cfreturn "null" />
<!--- BOOLEAN --->
<cfelseif ListFindNoCase("true,false", _data)>
<cfreturn _data />
<!--- EMPTY STRING --->
<cfelseif _data EQ "''" OR _data EQ '""'>
<cfreturn "" />
<!--- STRING --->
<cfelseif ReFind('^"[^\\"]*(?:\\.[^\\"]*)*"$', _data) EQ 1 OR ReFind("^'[^\\']*(?:\\.[^\\']*)*'$", _data) EQ 1>
<cfset _data = mid(_data, 2, Len(_data)-2) />
<!--- If there are any \b, \t, \n, \f, and \r, do extra processing
(required because ReplaceList() won't work with those) --->
<cfif Find("\b", _data) OR Find("\t", _data) OR Find("\n", _data) OR Find("\f", _data) OR Find("\r", _data)>
<cfset curCharIndex = 0 />
<cfset curChar = ""/>
<cfset dJSONString = ArrayNew(1) />
<cfloop condition="true">
<cfset curCharIndex = curCharIndex + 1 />
<cfif curCharIndex GT len(_data)>
<cfbreak />
<cfelse>
<cfset curChar = mid(_data, curCharIndex, 1) />
<cfif curChar EQ "\">
<cfset curCharIndex = curCharIndex + 1 />
<cfset curChar = mid(_data, curCharIndex,1) />
<cfset pos = listFind(unescapeVals2, curChar) />
<cfif pos>
<cfset ArrayAppend(dJSONString,ListGetAt(unescapetoVals2, pos)) />
<cfelse>
<cfset ArrayAppend(dJSONString,"\" & curChar) />
</cfif>
<cfelse>
<cfset ArrayAppend(dJSONString,curChar) />
</cfif>
</cfif>
</cfloop>
<cfreturn ArrayToList(dJSONString,"") />
<cfelse>
<cfreturn ReplaceList(_data, unescapeVals, unescapeToVals) />
</cfif>
<!--- ARRAY, STRUCT, OR QUERY --->
<cfelseif ( Left(_data, 1) EQ "[" AND Right(_data, 1) EQ "]" )
OR ( Left(_data, 1) EQ "{" AND Right(_data, 1) EQ "}" )>
<!--- Store the data type we're dealing with --->
<cfif Left(_data, 1) EQ "[" AND Right(_data, 1) EQ "]">
<cfset dataType = "array" />
<cfelseif ReFindNoCase('^\{"ROWCOUNT":[0-9]+,"COLUMNS":\[("[^"]+",?)+\],"DATA":\{("[^"]+":\[[^]]*\],?)+\}\}$', _data, 0) EQ 1 AND NOT arguments.strictMapping>
<cfset dataType = "queryByColumns" />
<cfelseif ReFindNoCase('^\{"COLUMNS":\[("[^"]+",?)+\],"DATA":\[(\[[^]]*\],?)+\]\}$', _data, 0) EQ 1 AND NOT arguments.strictMapping>
<cfset dataType = "query" />
<cfelse>
<cfset dataType = "struct" />
</cfif>
<!--- Remove the brackets --->
<cfset _data = Trim( Mid(_data, 2, Len(_data)-2) ) />
<!--- Deal with empty array/struct --->
<cfif Len(_data) EQ 0>
<cfif dataType EQ "array">
<cfreturn ar />
<cfelse>
<cfreturn st />
</cfif>
</cfif>
<!--- Loop through the string characters --->
<cfset dataSize = Len(_data) + 1 />
<cfloop condition="#i# LTE #dataSize#">
<cfset skipIncrement = false />
<!--- Save current character --->
<cfset char = Mid(_data, i, 1) />
<!--- If char is a quote, switch the quote status --->
<cfif char EQ '"'>
<cfset inQuotes = NOT inQuotes />
<!--- If char is escape character, skip the next character --->
<cfelseif char EQ "\" AND inQuotes>
<cfset i = i + 2 />
<cfset skipIncrement = true />
<!--- If char is a comma and is not in quotes, or if end of string, deal with data --->
<cfelseif (char EQ "," AND NOT inQuotes AND nestingLevel EQ 0) OR i EQ Len(_data)+1>
<cfset dataStr = Mid(_data, startPos, i-startPos) />
<!--- If data type is array, append data to the array --->
<cfif dataType EQ "array">
<cfset arrayappend( ar, deserializeFromJSON(dataStr, arguments.strictMapping) ) />
<!--- If data type is struct or query or queryByColumns... --->
<cfelseif dataType EQ "struct" OR dataType EQ "query" OR dataType EQ "queryByColumns">
<cfset dataStr = Mid(_data, startPos, i-startPos) />
<cfset colonPos = Find('":', dataStr) />
<cfif colonPos>
<cfset colonPos = colonPos + 1 />
<cfelse>
<cfset colonPos = Find(":", dataStr) />
</cfif>
<cfset structKey = Trim( Mid(dataStr, 1, colonPos-1) ) />
<!--- If needed, remove quotes from keys --->
<cfif Left(structKey, 1) EQ "'" OR Left(structKey, 1) EQ '"'>
<cfset structKey = Mid( structKey, 2, Len(structKey)-2 ) />
</cfif>
<cfset structVal = Mid( dataStr, colonPos+1, Len(dataStr)-colonPos ) />
<!--- If struct, add to the structure --->
<cfif dataType EQ "struct">
<cfset StructInsert( st, structKey, deserializeFromJSON(structVal, arguments.strictMapping) ) />
<!--- If query, build the query --->
<cfelseif dataType EQ "queryByColumns">
<cfif structKey EQ "rowcount">
<cfset qRows = deserializeFromJSON(structVal, arguments.strictMapping) />
<cfelseif structKey EQ "columns">
<cfset qCols = deserializeFromJSON(structVal, arguments.strictMapping) />
<cfset st = QueryNew(ArrayToList(qCols)) />
<cfif qRows>
<cfset QueryAddRow(st, qRows) />
</cfif>
<cfelseif structKey EQ "data">
<cfset qData = deserializeFromJSON(structVal, arguments.strictMapping) />
<cfset ar = StructKeyArray(qData) />
<cfloop from="1" to="#ArrayLen(ar)#" index="j">
<cfloop from="1" to="#st.recordcount#" index="qRows">
<cfset qCol = ar[j] />
<cfset QuerySetCell(st, qCol, qData[qCol][qRows], qRows) />
</cfloop>
</cfloop>
</cfif>
<cfelseif dataType EQ "query">
<cfif structKey EQ "columns">
<cfset qCols = deserializeFromJSON(structVal, arguments.strictMapping) />
<cfset st = QueryNew(ArrayToList(qCols)) />
<cfelseif structKey EQ "data">
<cfset qData = deserializeFromJSON(structVal, arguments.strictMapping) />
<cfloop from="1" to="#ArrayLen(qData)#" index="qRows">
<cfset QueryAddRow(st) />
<cfloop from="1" to="#ArrayLen(qCols)#" index="j">
<cfset qCol = qCols[j] />
<cfset QuerySetCell(st, qCol, qData[qRows][j], qRows) />
</cfloop>
</cfloop>
</cfif>
</cfif>
</cfif>
<cfset startPos = i + 1 />
<!--- If starting a new array or struct, add to nesting level --->
<cfelseif "{[" CONTAINS char AND NOT inQuotes>
<cfset nestingLevel = nestingLevel + 1 />
<!--- If ending an array or struct, subtract from nesting level --->
<cfelseif "]}" CONTAINS char AND NOT inQuotes>
<cfset nestingLevel = nestingLevel - 1 />
</cfif>
<cfif NOT skipIncrement>
<cfset i = i + 1 />
</cfif>
</cfloop>
<!--- Return appropriate value based on data type --->
<cfif dataType EQ "array">
<cfreturn ar />
<cfelse>
<cfreturn st />
</cfif>
<!--- INVALID JSON --->
<cfelse>
<cfthrow message="JSON parsing failure." />
</cfif>
</cffunction>
<cffunction
name="serializeToJSON"
access="public"
returntype="string"
output="false"
hint="Converts ColdFusion data into a JSON (JavaScript Object Notation) representation of the data.">
<cfargument
name="var"
type="any"
required="true"
hint="A ColdFusion data value or variable that represents one." />
<cfargument
name="serializeQueryByColumns"
type="boolean"
required="false"
default="false"
hint="A Boolean value that specifies how to serialize ColdFusion queries.
<ul>
<li><code>false</code>: (Default) Creates an object with two entries: an array of column names and an array of row arrays. This format is required by the HTML format cfgrid tag.</li>
<li><code>true</code>: Creates an object that corresponds to WDDX query format.</li>
</ul>">
<cfargument
name="strictMapping"
type="boolean"
required="false"
default="false"
hint="A Boolean value that specifies whether to convert the ColdFusion data strictly, as follows:
<ul>
<li><code>false:</code> (Default) Convert the ColdFusion data to a JSON string using ColdFusion data types.</li>
<li><code>true:</code> Convert the ColdFusion data to a JSON string using underlying Java/SQL data types.</li>
</ul>" />
<!--- VARIABLE DECLARATION --->
<cfset var jsonString = "" />
<cfset var tempVal = "" />
<cfset var arKeys = "" />
<cfset var colPos = 1 />
<cfset var md = "" />
<cfset var rowDel = "" />
<cfset var colDel = "" />
<cfset var className = "" />
<cfset var i = 1 />
<cfset var column = "" />
<cfset var datakey = "" />
<cfset var recordcountkey = "" />
<cfset var columnlist = "" />
<cfset var columnlistkey = "" />
<cfset var columnJavaTypes = "" />
<cfset var dJSONString = "" />
<cfset var escapeToVals = "\\,\"",\/,\b,\t,\n,\f,\r" />
<cfset var escapeVals = "\,"",/,#Chr(8)#,#Chr(9)#,#Chr(10)#,#Chr(12)#,#Chr(13)#" />
<cfset var _data = arguments.var />
<cfif arguments.strictMapping>
<!--- GET THE CLASS NAME --->
<cfset className = getClassName(_data) />
</cfif>
<!--- TRY STRICT MAPPING --->
<cfif Len(className) AND CompareNoCase(className,"java.lang.String") eq 0>
<cfreturn '"' & ReplaceList(_data, escapeVals, escapeToVals) & '"' />
<cfelseif Len(className) AND CompareNoCase(className,"java.lang.Boolean") eq 0>
<cfreturn ReplaceList(ToString(_data), 'YES,NO', 'true,false') />
<cfelseif Len(className) AND CompareNoCase(className,"java.lang.Integer") eq 0>
<cfreturn ToString(_data) />
<cfelseif Len(className) AND CompareNoCase(className,"java.lang.Long") eq 0>
<cfreturn ToString(_data) />
<cfelseif Len(className) AND CompareNoCase(className,"java.lang.Float") eq 0>
<cfreturn ToString(_data) />
<cfelseif Len(className) AND CompareNoCase(className,"java.lang.Double") eq 0>
<cfreturn ToString(_data) />
<!--- BINARY --->
<cfelseif IsBinary(_data)>
<cfthrow message="JSON serialization failure: Unable to serialize binary data to JSON." />
<!--- BOOLEAN --->
<cfelseif IsBoolean(_data) AND NOT IsNumeric(_data)>
<cfreturn ReplaceList(YesNoFormat(_data), 'Yes,No', 'true,false') />
<!--- NUMBER --->
<cfelseif IsNumeric(_data)>
<cfif getClassName(_data) eq "java.lang.String">
<cfreturn Val(_data).toString() />
<cfelse>
<cfreturn _data.toString() />
</cfif>
<!--- DATE --->
<cfelseif IsDate(_data)>
<cfreturn '"#DateFormat(_data, "mmmm, dd yyyy")# #TimeFormat(_data, "HH:mm:ss")#"' />
<!--- STRING --->
<cfelseif IsSimpleValue(_data)>
<cfreturn '"' & ReplaceList(_data, escapeVals, escapeToVals) & '"' />
<!--- RAILO XML --->
<cfelseif StructKeyExists(server,"railo") and IsXML(_data)>
<cfreturn '"' & ReplaceList(ToString(_data), escapeVals, escapeToVals) & '"' />
<!--- CUSTOM FUNCTION --->
<cfelseif IsCustomFunction(_data)>
<cfreturn serializeToJSON( GetMetadata(_data), arguments.serializeQueryByColumns, arguments.strictMapping) />
<!--- OBJECT --->
<cfelseif IsObject(_data)>
<cfreturn "{}" />
<!--- ARRAY --->
<cfelseif IsArray(_data)>
<cfset dJSONString = ArrayNew(1) />
<cfloop from="1" to="#ArrayLen(_data)#" index="i">
<cfset tempVal = serializeToJSON( _data[i], arguments.serializeQueryByColumns, arguments.strictMapping ) />
<cfset ArrayAppend(dJSONString,tempVal) />
</cfloop>
<cfreturn "[" & ArrayToList(dJSONString,",") & "]" />
<!--- STRUCT --->
<cfelseif IsStruct(_data)>
<cfset dJSONString = ArrayNew(1) />
<cfset arKeys = StructKeyArray(_data) />
<cfloop from="1" to="#ArrayLen(arKeys)#" index="i">
<cfset tempVal = serializeToJSON(_data[ arKeys[i] ], arguments.serializeQueryByColumns, arguments.strictMapping ) />
<cfset ArrayAppend(dJSONString,'"' & arKeys[i] & '":' & tempVal) />
</cfloop>
<cfreturn "{" & ArrayToList(dJSONString,",") & "}" />
<!--- QUERY --->
<cfelseif IsQuery(_data)>
<cfset dJSONString = ArrayNew(1) />
<!--- Add query meta data --->
<cfset recordcountKey = "ROWCOUNT" />
<cfset columnlistKey = "COLUMNS" />
<cfset columnlist = "" />
<cfset dataKey = "DATA" />
<cfset md = GetMetadata(_data) />
<cfset columnJavaTypes = StructNew() />
<cfloop from="1" to="#ArrayLen(md)#" index="column">
<cfset columnlist = ListAppend(columnlist,UCase(md[column].Name),',') />
<cfif StructKeyExists(md[column],"TypeName")>
<cfset columnJavaTypes[md[column].Name] = getJavaType(md[column].TypeName) />
<cfelse>
<cfset columnJavaTypes[md[column].Name] = "" />
</cfif>
</cfloop>
<cfif arguments.serializeQueryByColumns>
<cfset ArrayAppend(dJSONString,'"#recordcountKey#":' & _data.recordcount) />
<cfset ArrayAppend(dJSONString,',"#columnlistKey#":[' & ListQualify(columnlist, '"') & ']') />
<cfset ArrayAppend(dJSONString,',"#dataKey#":{') />
<cfset colDel = "">
<cfloop list="#columnlist#" delimiters="," index="column">
<cfset ArrayAppend(dJSONString,colDel) />
<cfset ArrayAppend(dJSONString,'"#column#":[') />
<cfset rowDel = "">
<cfloop from="1" to="#_data.recordcount#" index="i">
<cfset ArrayAppend(dJSONString,rowDel) />
<cfif (arguments.strictMapping or StructKeyExists(server,"railo")) AND Len(columnJavaTypes[column])>
<cfset tempVal = serializeToJSON( JavaCast(columnJavaTypes[column],_data[column][i]), arguments.serializeQueryByColumns, arguments.strictMapping ) />
<cfelse>
<cfset tempVal = serializeToJSON( _data[column][i], arguments.serializeQueryByColumns, arguments.strictMapping ) />
</cfif>
<cfset ArrayAppend(dJSONString,tempVal) />
<cfset rowDel = ",">
</cfloop>
<cfset ArrayAppend(dJSONString,']') />
<cfset colDel = ",">
</cfloop>
<cfset ArrayAppend(dJSONString,'}') />
<cfelse>
<cfset ArrayAppend(dJSONString,'"#columnlistKey#":[' & ListQualify(columnlist, '"') & ']') />
<cfset ArrayAppend(dJSONString,',"#dataKey#":[') />
<cfset rowDel = "">
<cfloop from="1" to="#_data.recordcount#" index="i">
<cfset ArrayAppend(dJSONString,rowDel) />
<cfset ArrayAppend(dJSONString,'[') />
<cfset colDel = "">
<cfloop list="#columnlist#" delimiters="," index="column">
<cfset ArrayAppend(dJSONString,colDel) />
<cfif (arguments.strictMapping or StructKeyExists(server,"railo")) AND Len(columnJavaTypes[column])>
<cfset tempVal = serializeToJSON( JavaCast(columnJavaTypes[column],_data[column][i]), arguments.serializeQueryByColumns, arguments.strictMapping ) />
<cfelse>
<cfset tempVal = serializeToJSON( _data[column][i], arguments.serializeQueryByColumns, arguments.strictMapping ) />
</cfif>
<cfset ArrayAppend(dJSONString,tempVal) />
<cfset colDel=","/>
</cfloop>
<cfset ArrayAppend(dJSONString,']') />
<cfset rowDel = "," />
</cfloop>
<cfset ArrayAppend(dJSONString,']') />
</cfif>
<cfreturn "{" & ArrayToList(dJSONString,"") & "}">
<!--- XML --->
<cfelseif IsXML(_data)>
<cfreturn '"' & ReplaceList(ToString(_data), escapeVals, escapeToVals) & '"' />
<!--- UNKNOWN OBJECT TYPE --->
<cfelse>
<cfreturn "{}" />
</cfif>
</cffunction>
<cffunction
name="getJavaType"
access="private"
returntype="string"
output="false"
hint="Maps SQL to Java types. Returns blank string for unhandled SQL types.">
<cfargument
name="sqlType"
type="string"
required="true"
hint="A SQL datatype." />
<cfswitch expression="#arguments.sqlType#">
<cfcase value="bit">
<cfreturn "boolean" />
</cfcase>
<cfcase value="tinyint,smallint,integer">
<cfreturn "int" />
</cfcase>
<cfcase value="bigint">
<cfreturn "long" />
</cfcase>
<cfcase value="real,float">
<cfreturn "float" />
</cfcase>
<cfcase value="double">
<cfreturn "double" />
</cfcase>
<cfcase value="char,varchar,longvarchar">
<cfreturn "string" />
</cfcase>
<cfdefaultcase>
<cfreturn "" />
</cfdefaultcase>
</cfswitch>
</cffunction>
<cffunction
name="getClassName"
access="private"
returntype="string"
output="false"
hint="Returns a variable's underlying java Class name.">
<cfargument
name="data"
type="any"
required="true"
hint="A variable." />
<!--- GET THE CLASS NAME --->
<cftry>
<cfreturn arguments.data.getClass().getName() />
<cfcatch type="any">
<cfreturn "" />
</cfcatch>
</cftry>
</cffunction>
</cfcomponent>
+6 -23
View File
@@ -1,26 +1,9 @@
<cfcomponent extends="taffy.core.baseSerializer">
component extends="taffy.core.baseSerializer" {
<!--- <cfset variables.jsonUtil = application.jsonUtil />
variables.jsonUtil = application.jsonUtil;
<cffunction
name="getAsJson"
output="false"
taffy:mime="application/json"
taffy:default="true">
<cfreturn variables.jsonUtil.serialize(variables.data) />
</cffunction> --->
<cffunction
name="getAsJson"
output="false"
taffy:mime="application/json"
taffy:default="true">
<cfreturn variables.jsonUtil.serialize(variables.data) />
</cffunction>
public function getAsJson() output="false" taffy_mime="application/json" taffy_default="true" {
return variables.jsonUtil.serialize(variables.data);
}
<cffunction name="setJSONUtil" output="false">
<cfargument name="JSONUtil" required="true" />
<cfset variables.jsonUtil = arguments.JSONUtil />
</cffunction>
</cfcomponent>
}
+44 -52
View File
@@ -1,62 +1,54 @@
<cfcomponent implements="taffy.bonus.ILogAdapter">
component implements="taffy.bonus.ILogAdapter" {
<cffunction name="init">
<cfargument name="config" />
<cfargument name="tracker" />
public function init(config, tracker="") {
if (structKeyExists(arguments, "tracker") && isObject(arguments.tracker)) {
// used to inject mocking object for testing
variables.blhq = arguments.tracker;
} else {
var svc = "bugLog.client.bugLogService";
if (structKeyExists(arguments.config, "service")) {
svc = arguments.config.service;
}
<!--- <cfdump var="#arguments.config#" abort="true" /> --->
<cfif structKeyExists(arguments, "tracker")>
<!--- used to inject mocking object for testing --->
<cfset variables.blhq = arguments.tracker />
<cfelse>
<cfset var svc = "bugLog.client.bugLogService" />
<cfif structKeyExists( arguments.config, "service" )>
<cfset svc = arguments.config.service />
</cfif>
variables.blhq = createObject("component", svc);
variables.blhq.init(argumentCollection=arguments.config);
}
<cfset variables.blhq = createObject("component", svc) />
<cfset variables.blhq.init(
argumentCollection=arguments.config
) />
</cfif>
param name="arguments.config.message" default="Exception trapped in API";
variables.message = arguments.config.message;
<cfparam name="arguments.config.message" default="Exception trapped in API" />
<cfset variables.message = arguments.config.message />
return this;
}
<cfreturn this />
</cffunction>
public function saveLog(exception) {
var msg = '';
<cffunction name="saveLog">
<cfargument name="exception" />
if (structKeyExists(exception, 'rootcause') && structKeyExists(exception.rootcause, 'cause') && structKeyExists(exception.rootcause.cause, 'message')) {
msg = exception.rootcause.cause.message;
} else if (structKeyExists(exception, 'cause') && structKeyExists(exception.cause, 'message')) {
msg = exception.cause.message;
} else if (structKeyExists(exception, 'message')) {
msg = exception.message;
} else {
msg = variables.message;
}
<cfset var msg = '' />
// You can use addDebugData() in resources to set this value
if (structKeyExists(request, "debugData") and !structKeyExists(exception, "extraInfo")) {
exception.extraInfo = request.debugData;
}
<cfif structKeyExists(exception, 'rootcause') && structKeyExists(exception.rootcause, 'cause') && structKeyExists(exception.rootcause.cause, 'message')>
<cfset msg = exception.rootcause.cause.message />
<cfelseif structKeyExists(exception, 'cause') && structKeyExists(exception.cause, 'message')>
<cfset msg = exception.cause.message />
<cfelseif structKeyExists(exception, 'message')>
<cfset msg = exception.message />
<cfelse>
<cfset msg = variables.message />
</cfif>
var reqHeaders = getHTTPRequestData().headers;
var reqBody = getHTTPRequestData().content;
// on input with content-type "application/json" CF seems to expose it as binary data. Here we convert it back to plain text
if (isBinary(reqBody)) {
reqBody = charsetEncode(reqBody, "UTF-8");
}
if (isJson(reqBody)) {
reqBody = deserializeJson(reqBody);
}
<!--- You can use addDebugData() in resources to set this value --->
<cfif structKeyExists(request, "debugData") and not structKeyExists(exception, "extraInfo")>
<cfset exception.extraInfo = request.debugData />
</cfif>
variables.blhq.notifyService(msg, arguments.exception, { request_body: reqBody, request_headers: reqHeaders });
}
<cfset var reqHeaders = getHTTPRequestData().headers />
<cfset var reqBody = getHTTPRequestData().content />
<!--- on input with content-type "application/json" CF seems to expose it as binary data. Here we convert it back to plain text --->
<cfif isBinary(reqBody)>
<cfset reqBody = charsetEncode(reqBody, "UTF-8") />
</cfif>
<cfif isJson(reqBody)>
<cfset reqBody = deserializeJson( reqBody ) />
</cfif>
<cfset variables.blhq.notifyService(msg, arguments.exception, { request_body: reqBody, request_headers: reqHeaders }) />
</cffunction>
</cfcomponent>
}
+110 -125
View File
@@ -1,146 +1,131 @@
<!---
Adapter Path: taffy.bonus.LogToBugsnag
Configuration Options: (structure)
/**
* Adapter Path: taffy.bonus.LogToBugsnag
* Configuration Options: (structure)
*
* variables.framework.exceptionLogAdapterConfig = {
* apiKey = "c9d60ae4c7e70c4b6c4ebd3e8056d2b8",
* appVersion = "1.1.3",
* releaseStage = "production"
* };
*
* apiKey: The API Key associated with the project
* appVersion: The version number of the application which generated the error
* releaseStage: The release stage that this error occurred in (e.g "development", "staging" or "production")
*/
component implements="taffy.bonus.ILogAdapter" {
variables.framework.exceptionLogAdapterConfig = {
apiKey = "c9d60ae4c7e70c4b6c4ebd3e8056d2b8",
appVersion = "1.1.3",
releaseStage = "production"
};
/**
* Initializes this logger
*/
public function init(config, tracker="") hint="I accept a configuration structure to setup and return myself" {
variables.config = {};
structAppend(variables.config, arguments.config, true);
return this;
}
apiKey: The API Key associated with the project
appVersion: The version number of the application which generated the error
releaseStage: The release stage that this error occurred in (e.g "development", "staging" or "production")
--->
<cfcomponent implements="taffy.bonus.ILogAdapter">
<!---
Initializes this logger
--->
<cffunction name="init" hint="I accept a configuration structure to setup and return myself">
<cfargument name="config" />
<cfargument name="tracker" />
/**
* Logs or notifies the specified exception
*/
public function saveLog(exception) hint="I log or otherwise notify you of an exception" {
var payload = {};
<!--- copy settings into adapter instance data --->
<cfset variables.config = structNew() />
<cfset structAppend(variables.config, arguments.config, true) />
// Add Project API key to payload
payload["apiKey"] = variables.config.apiKey;
<cfreturn this />
</cffunction>
// Add notifier info to payload
payload["notifier"] = {};
payload["notifier"]["name"] = "Taffy";
payload["notifier"]["version"] = "1.0";
payload["notifier"]["url"] = "https://github.com/atuttle/Taffy";
<!---
Logs or notifies the specified exception
--->
<cffunction name="saveLog" hint="I log or otherwise notify you of an exception">
<cfargument name="exception" />
// Add exception details to payload
payload["events"] = [];
payload["events"][1] = {};
payload["events"][1]["payloadVersion"] = "2";
payload["events"][1]["exceptions"] = [];
payload["events"][1]["exceptions"][1] = convertException(arguments.exception);
<!--- Define local variables --->
<cfset var payload = structNew() />
// Add application details to payload
payload["events"][1]["app"] = {};
payload["events"][1]["app"]["appVersion"] = variables.config.appVersion;
payload["events"][1]["app"]["releaseStage"] = variables.config.releaseStage;
<!--- Add Project API key to payload --->
<cfset payload["apiKey"] = variables.config.apiKey />
// Add some metadata to payload
payload["events"][1]["metaData"] = {};
payload["events"][1]["metaData"]["request"] = {};
payload["events"][1]["metaData"]["request"]["remoteAddr"] = cgi.remote_addr;
payload["events"][1]["metaData"]["request"]["requestMethod"] = cgi.request_method;
payload["events"][1]["metaData"]["request"]["requestUrl"] = cgi.request_url;
<!--- Add notifier info to payload --->
<cfset payload["notifier"] = structNew() />
<cfset payload["notifier"]["name"] = "Taffy" />
<cfset payload["notifier"]["version"] = "1.0" />
<cfset payload["notifier"]["url"] = "https://github.com/atuttle/Taffy" />
// Send log to Bugsnag
cfhttp(url="https://notify.bugsnag.com", method="post") {
cfhttpparam(type="header", name="Content-Type", value="application/json");
cfhttpparam(type="body", value=serializeJSON(payload));
}
}
<!--- Add exception details to payload --->
<cfset payload["events"] = arrayNew(1) />
<cfset payload["events"][1] = structNew() />
<cfset payload["events"][1]["payloadVersion"] = "2" />
<cfset payload["events"][1]["exceptions"] = arrayNew(1) />
<cfset payload["events"][1]["exceptions"][1] = convertException(arguments.exception) />
/**
* Converts the specified exception to be added to the payload
*/
private struct function convertException(required struct exception) output="false" {
var root = "";
var exceptionElement = {};
var tagContextElement = "";
<!--- Add application details to payload --->
<cfset payload["events"][1]["app"] = structNew() />
<cfset payload["events"][1]["app"]["appVersion"] = variables.config.appVersion />
<cfset payload["events"][1]["app"]["releaseStage"] = variables.config.releaseStage />
// Get the root exception
if (structKeyExists(exception, "rootCause")) {
root = arguments.exception.rootCause;
} else {
root = arguments.exception;
}
<!--- Add some metadata to payload --->
<cfset payload["events"][1]["metaData"] = structNew() />
<cfset payload["events"][1]["metaData"]["request"] = structNew() />
<cfset payload["events"][1]["metaData"]["request"]["remoteAddr"] = cgi.remote_addr />
<cfset payload["events"][1]["metaData"]["request"]["requestMethod"] = cgi.request_method />
<cfset payload["events"][1]["metaData"]["request"]["requestUrl"] = cgi.request_url />
// Add type and message to payload
exceptionElement["errorClass"] = root.type;
exceptionElement["message"] = root.message;
<!--- Send log to Bugsnag --->
<cfhttp url="https://notify.bugsnag.com" method="post">
<cfhttpparam type="header" name="Content-Type" value="application/json" />
<cfhttpparam type="body" value="#serializeJSON(payload)#" />
</cfhttp>
</cffunction>
// Build stack trace
exceptionElement["stacktrace"] = [];
for (tagContextElement in root.TagContext) {
arrayAppend(exceptionElement["stacktrace"], convertTagContextElement(tagContextElement));
}
<!---
Converts the specified exception to be added to the payload
--->
<cffunction name="convertException" access="private" returntype="struct" output="false">
<cfargument name="exception" type="struct" required="true" />
return exceptionElement;
}
<!--- Define local variables --->
<cfset var root = "" />
<cfset var exceptionElement = structNew() />
<cfset var tagContextElement = "" />
/**
* Converts the specified Tag Context element to be included in the stack trace array
*/
private struct function convertTagContextElement(required struct tagContextElement) output="false" {
var stackTraceElement = {};
<!--- Get the root exception --->
<cfif structKeyExists(exception, "rootCause")>
<cfset root = arguments.exception.rootCause />
<cfelse>
<cfset root = arguments.exception />
</cfif>
// Add stack trace data
stackTraceElement["file"] = arguments.tagContextElement.template;
stackTraceElement["lineNumber"] = arguments.tagContextElement.line;
stackTraceElement["columnNumber"] = arguments.tagContextElement.column;
stackTraceElement["method"] = "Unknown function";
<!--- Add type and message to payload --->
<cfset exceptionElement["errorClass"] = root.type />
<cfset exceptionElement["message"] = root.message />
// Add code details
if (structKeyExists(arguments.tagContextElement, "codePrintPlain")) {
stackTraceElement["code"] = convertCodePrint(arguments.tagContextElement.codePrintPlain);
}
<!--- Build stack trace --->
<cfset exceptionElement["stacktrace"] = arrayNew(1) />
<cfloop array="#root.TagContext#" index="tagContextElement">
<cfset arrayAppend(exceptionElement["stacktrace"], convertTagContextElement(tagContextElement)) />
</cfloop>
return stackTraceElement;
}
<cfreturn exceptionElement />
</cffunction>
/**
* Converts the specified code details to be included to the stack trace element
*/
private struct function convertCodePrint(required string codePrintText) output="false" {
var codeLines = {};
var split = listToArray(arguments.codePrintText, chr(10));
var line = "";
<!---
Converts the specified Tag Context element to be included in the strack trace array
---->
<cffunction name="convertTagContextElement" access="private" returntype="struct" output="false">
<cfargument name="tagContextElement" type="struct" required="true" />
// Add code lines
for (line in split) {
structInsert(codeLines, listFirst(line, ":"), trim(listRest(line, ":")));
}
<!--- Define local variables --->
<cfset var stackTraceElement = structNew() />
return codeLines;
}
<!--- Add stack trace data --->
<cfset stackTraceElement["file"] = arguments.tagContextElement.template />
<cfset stackTraceElement["lineNumber"] = arguments.tagContextElement.line />
<cfset stackTraceElement["columnNumber"] = arguments.tagContextElement.column />
<cfset stackTraceElement["method"] = "Unknown function" />
<!--- Add code details --->
<cfif structKeyExists(arguments.tagContextElement, "codePrintPlain")>
<cfset stackTraceElement["code"] = convertCodePrint(arguments.tagContextElement.codePrintPlain) />
</cfif>
<cfreturn stackTraceElement />
</cffunction>
<!---
Converts the specified code details to be included to the strack trace element
--->
<cffunction name="convertCodePrint" access="private" returntype="struct" output="false">
<cfargument name="codePrintText" type="string" required="true" />
<!--- Define local variables --->
<cfset var codeLines = structNew() />
<cfset var split = listToArray(arguments.codePrintText, chr(10)) />
<cfset var line = "" />
<!--- Add code lines --->
<cfloop array="#split#" index="line">
<cfset structInsert(codeLines, listFirst(line, ":"), trim(listRest(line, ":"))) />
</cfloop>
<cfreturn codeLines />
</cffunction>
</cfcomponent>
}
+7 -10
View File
@@ -1,13 +1,10 @@
<cfcomponent implements="taffy.bonus.ILogAdapter">
component implements="taffy.bonus.ILogAdapter" {
<cffunction name="init">
<cfargument name="config" />
<cfargument name="tracker" />
<cfreturn this />
</cffunction>
public function init(config, tracker) {
return this;
}
<cffunction name="saveLog">
<cfargument name="exception" />
</cffunction>
public function saveLog(exception) {
}
</cfcomponent>
}
+43 -51
View File
@@ -1,61 +1,53 @@
<cfcomponent implements="taffy.bonus.ILogAdapter">
component implements="taffy.bonus.ILogAdapter" {
<cffunction name="init">
<cfargument name="config" />
<cfargument name="tracker" hint="unused" default="" />
public function init(config, tracker="") hint="unused tracker" {
variables.config = {};
structAppend(variables.config, arguments.config, true);
return this;
}
<!--- copy settings into adapter instance data --->
<cfset variables.config = {}>
<cfset structAppend( variables.config, arguments.config, true ) />
public function saveLog(exception) {
var local = {};
<cfreturn this />
</cffunction>
variables.config = removeEmailPrefix(variables.config);
<cffunction name="saveLog">
<cfargument name="exception" />
// to conform to the cfmail attribute name and be backward compatible with emailSubj
variables.config.subject = variables.config.subj;
<cfset var local = StructNew() />
local.attributeCollection = variables.config;
<cfset variables.config = removeEmailPrefix(variables.config)>
cfmail(attributeCollection=local.attributeCollection) {
if (variables.config.type eq "text") {
writeOutput("Exception Report
<!--- to conform to the cfmail attribute name and be backward compatible with emailSubj --->
<cfset variables.config.subject = variables.config.subj>
Exception Timestamp: #dateformat(now(), 'yyyy-mm-dd')# #timeformat(now(), 'HH:MM:SS tt')#
<cfset local.attributeCollection = variables.config>
");
writeDump(var=arguments.exception, format="text");
if (isDefined('request.debugData')) {
writeDump(var=request.debugData, label="debug data", format="text");
}
} else {
writeOutput("<h2>Exception Report</h2>
<p><strong>Exception Timestamp:</strong> #dateformat(now(), 'yyyy-mm-dd')# #timeformat(now(), 'HH:MM:SS tt')#</p>");
writeDump(arguments.exception);
if (isDefined('request.debugData')) {
writeDump(var=request.debugData, label="debug data");
}
}
}
}
<cfmail attributeCollection="#local.attributeCollection#">
<cfif variables.config.type eq "text">
Exception Report
private struct function removeEmailPrefix(required struct configAttributes) output="false" hint="removes all email prefix from the config attributes" {
var configAttributeName = "";
var configAttributeValue = "";
var newConfig = {};
var configAttributeNameWithoutEmailPrefix = "";
for (configAttributeName in arguments.configAttributes) {
configAttributeNameWithoutEmailPrefix = replaceNoCase(configAttributeName, "email", "", "one");
newConfig[configAttributeNameWithoutEmailPrefix] = arguments.configAttributes[configAttributeName];
}
return newConfig;
}
Exception Timestamp: <cfoutput>#dateformat(now(), 'yyyy-mm-dd')# #timeformat(now(), 'HH:MM:SS tt')#</cfoutput>
<cfdump var="#arguments.exception#" format="text" />
<cfif isDefined('request.debugData')>
<cfdump var="#request.debugData#" label="debug data" format="text"/>
</cfif>
<cfelse>
<h2>Exception Report</h2>
<p><strong>Exception Timestamp:</strong> <cfoutput>#dateformat(now(), 'yyyy-mm-dd')# #timeformat(now(), 'HH:MM:SS tt')#</cfoutput></p>
<cfdump var="#arguments.exception#" />
<cfif isDefined('request.debugData')>
<cfdump var="#request.debugData#" label="debug data" />
</cfif>
</cfif>
</cfmail>
</cffunction>
<cffunction name="removeEmailPrefix" output="false" access="private" returntype="struct" hint="removes all email prefix from the config attributes">
<cfargument name="configAttributes" required="true" type="struct" />
<cfset var configAttributeName="" />
<cfset var configAttributeValue = "" />
<cfset var newConfig = {} />
<cfloop collection="#arguments.configAttributes#" item="configAttributeName">
<cfset configAttributeNameWithoutEmailPrefix = replaceNoCase(configAttributeName, "email", "", "one") />
<cfset newConfig[configAttributeNameWithoutEmailPrefix] = arguments.configAttributes[configAttributeName] />
</cfloop>
<cfreturn newConfig />
</cffunction>
</cfcomponent>
}
+13 -15
View File
@@ -1,19 +1,17 @@
<cfcomponent implements="taffy.bonus.ILogAdapter">
component implements="taffy.bonus.ILogAdapter" {
<cffunction name="init">
<cfargument name="config" />
<cfargument name="tracker" default="#createObject("component", "Hoth.HothTracker")#" />
<cfset variables.hothtracker = arguments.tracker />
<cfset variables.hothtracker.init(
public function init(config, tracker=createObject("component", "Hoth.HothTracker")) {
variables.hothtracker = arguments.tracker;
variables.hothtracker.init(
createObject("component", arguments.config)
) />
<cfreturn this />
</cffunction>
);
return this;
}
<cffunction name="saveLog">
<cfargument name="exception" />
<cfset local.result = variables.HothTracker.track(arguments.exception) />
<cfheader name="X-HOTH-LOGGED-EXCEPTION" value="#local.result#" />
</cffunction>
public function saveLog(exception) {
var local = {};
local.result = variables.HothTracker.track(arguments.exception);
cfheader(name="X-HOTH-LOGGED-EXCEPTION", value=local.result);
}
</cfcomponent>
}
+14 -20
View File
@@ -1,23 +1,17 @@
<cfcomponent implements="taffy.bonus.ILogAdapter">
component implements="taffy.bonus.ILogAdapter" {
<cffunction name="init">
<cfargument name="config" />
<cfargument name="tracker" hint="unused" default="" />
public function init(config, tracker="") hint="unused tracker" {
variables.config = {};
structAppend(variables.config, arguments.config, true);
return this;
}
<!--- copy settings into adapter instance data --->
<cfset variables.config = {}>
<cfset structAppend( variables.config, arguments.config, true ) />
public function saveLog(exception) {
var logdump = "";
savecontent variable="logdump" {
writeDump(var=arguments.exception, format="text");
}
writeLog(file=variables.config.logfile, text=logdump, type="Error");
}
<cfreturn this />
</cffunction>
<cffunction name="saveLog">
<cfargument name="exception" />
<cfset var logdump = "">
<!--- build dump --->
<cfsavecontent variable="logdump"><cfdump var="#arguments.exception#" format="text"></cfsavecontent>
<!--- write to log --->
<cflog file="#variables.config.logfile#" text="#logdump#" type="Error">
</cffunction>
</cfcomponent>
}
+14 -17
View File
@@ -1,20 +1,17 @@
<cfcomponent implements="taffy.bonus.ILogAdapter">
component implements="taffy.bonus.ILogAdapter" {
<cffunction name="init">
<cfargument name="config" />
<cfargument name="tracker" hint="unused" default="" />
<cfreturn this />
</cffunction>
public function init(config, tracker="") hint="unused tracker" {
return this;
}
<cffunction name="saveLog">
<cfargument name="exception" />
<cfcontent type="text/html" />
<cfheader statuscode="500" statustext="Unhandled API Error" />
<cfdump var="#arguments#" />
<cfif isDefined('request.debugData')>
<cfdump var="#request.debugData#" label="debug data" />
</cfif>
<cfabort />
</cffunction>
public function saveLog(exception) {
cfcontent(type="text/html");
cfheader(statuscode="500", statustext="Unhandled API Error");
writeDump(arguments);
if (isDefined('request.debugData')) {
writeDump(var=request.debugData, label="debug data");
}
abort;
}
</cfcomponent>
}