I am using this library for OAuth v1.0 to connect to QuickBooks Online API. I am successfully able to use three legged authentication and get back access tokens. I am also able to do connect to most endpoints with no problem. However, I am having issue connecting to endpoints with URL parameters.
For example, this URL returns with no issue:
https://sandbox-quickbooks.api.intuit.com/v3/company/123145723805019/customer/8
However, this URL returns with SignatureBaseString: error 401 unAuthorized.
//sandbox-quickbooks.api.intuit.com/v3/company/123145723805019/query?query=select * from customer
Am I misunderstanding something about how to access endpoints with URL parameters in OAuth? Any help or insight would be appreciated.
Working Code:
<cfset oAuthRequest = new com.brianflove.oauth.Request()>
<cfset oAuthConsumer = new com.brianflove.oauth.Consumer()>
<cfset oauthConsumer.setSecret(CONSUMER_SECRET)>
<cfset oauthConsumer.setKey(CONSUMER_KEY)>
<cfset oAuthRequest.setMethod("GET")>
<cfset oAuthRequest.setUrl("https://sandbox-quickbooks.api.intuit.com/v3/company/123145723805019/customer/" & randrange(1,8))>
<cfset oAuthRequest.setConsumer(oAuthConsumer)>
<cfset oAuthRequest.setToken(session.token)>
<!---use HMAC-SHA1 signature method--->
<cfset signatureMethod = new com.brianflove.oauth.methods.HmacSha1SignatureMethod()>
<!---sign request--->
<cfset oAuthRequest.signWithSignatureMethod(signatureMethod=signatureMethod)>
<!---POST using request URL--->
<cfset httpRequest = new Http()>
<cfset httpRequest.setUrl(oAuthRequest.getUrl())>
<cfset httpRequest.setMethod(oAuthRequest.getMethod())>
<cfset httpRequest.addParam(type="header", name="Authorization", value=oAuthRequest.toHeader())>
<cfset httpRequest.addParam(type="header", name="Accept", value="application/json") />
<cfset httpRequest.setCharset("utf-8")>
<cfset httpResult = httpRequest.send().getPrefix()>
<cfdump var="#httpResult.filecontent#">
Not Working Code:
<cfset oAuthRequest = new com.brianflove.oauth.Request()>
<cfset oAuthConsumer = new com.brianflove.oauth.Consumer()>
<cfset oauthConsumer.setSecret(CONSUMER_SECRET)>
<cfset oauthConsumer.setKey(CONSUMER_KEY)>
<cfset oAuthRequest.setMethod("GET")>
<cfset oAuthRequest.setUrl("https://sandbox-quickbooks.api.intuit.com/v3/company/123145723805019/query?query=select * from customer") />
<cfset oAuthRequest.setConsumer(oAuthConsumer)>
<cfset oAuthRequest.setToken(session.token)>
<!---use HMAC-SHA1 signature method--->
<cfset signatureMethod = new com.brianflove.oauth.methods.HmacSha1SignatureMethod()>
<!---sign request--->
<cfset oAuthRequest.signWithSignatureMethod(signatureMethod=signatureMethod)>
<!---POST using request URL--->
<cfset httpRequest = new Http()>
<cfset httpRequest.setUrl(oAuthRequest.getUrl())>
<cfset httpRequest.setMethod(oAuthRequest.getMethod())>
<cfset httpRequest.addParam(type="header", name="Authorization", value=oAuthRequest.toHeader())>
<cfset httpRequest.addParam(type="header", name="Accept", value="application/json") />
<cfset httpRequest.setCharset("utf-8")>
<cfset httpResult = httpRequest.send().getPrefix()>
<cfdump var="#httpResult.filecontent#">
Error Response:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<IntuitResponse time="2016-12-01T06:12:00.999-08:00" xmlns="http://schema.intuit.com/finance/v3">
<Fault type="AUTHENTICATION">
<Error code="3200">
<Message>message=ApplicationAuthenticationFailed; errorCode=003200; statusCode=401</Message>
<Detail>SignatureBaseString: GET&https%3A%2F%2Fsandbox-quickbooks.api.intuit.com%2Fv3%2Fcompany%2F123145723805019%2Fquery&oauth_consumer_key%3DqyprdTVZH2CtDAXewG1YQKQYzUssYH%26oauth_nonce%3D420ADB0BF9EF309B785C531EEE8A7AAF%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1480601520%26oauth_token%3Dqyprd5g2WEiaxaVyI3MqeXqRvxvi26cXuauyMtFQaMZHdjVT%26oauth_version%3D1.0%26query%3Dselect%2520%252A%2520from%2520customer</Detail>
</Error>
</Fault>
</IntuitResponse>
Encode the query statement before passing it into the URL.
Use the below method to perform the encoding:
<cffunction name="encodePercent" returntype="string" access="public"
description="RFC 3986 encoding - keep [ALPHA, DIGIT, '-', '.', '_', '~'], %-encode the rest -> decoding '~', correctly encoding spaces('+') and '*'">
<cfargument name="sValue" required="true" type="string" hint="value to encode">
<cfargument name="sEncoding" required="false" type="string" default="UTF-8" hint="encoding">
<cfset var sResult = "">
<!--- using javacast to call the appropriate encode method --->
<cfif Len(arguments.sValue)>
<cfset sResult = CreateObject("java","java.net.URLEncoder").
encode(JavaCast("String",arguments.sValue), JavaCast("String",arguments.sEncoding))>
<cfset sResult = Replace(sResult,"+","%20","all")>
<cfset sResult = Replace(sResult,"*","%2A","all")>
<cfset sResult = Replace(sResult,"%7E","~","all")>
</cfif>
<cfreturn sResult>
</cffunction>
You can keep the default value of the "sEncoding" argument as is.
Related
I put my project on a new server where I am using ColdFusion 2016 but it is failing while running the following lines:
<cfset fastFileWriter = createObject("java", "FastResultsetToFile")>
<cfset fastFileWriter.exportResultsetToFile(myQuery, "#TempFile#", ',', "UTF-8")>
In ColdFusion 9, where my old server is, it is working just fine. Does anyone knows why this is happening and how to make this work for ColdFusion 2016?
Here is a bigger picture of the code:
<cfset yopath = "#application.masterpath#/platform_a/reports/pods/#pid#" />
<cfset acfile = "outbound_export_#session.callmeasurement_uid#.csv" />
<cfset TempFile = "#yopath#/#acfile#">
<cfif FileExists(TempFile)>
<cffile action="delete" file="#TempFile#" >
</cfif>
<cfset myQuery = QueryNew("Team_Member, Calls, Unique, Live_Connections, Rescued_Calls")>
<cfloop query = "pull_staff">
<cfset newrow = QueryAddRow(myQuery,1)>
<cfset temp = QuerySetCell(myQuery, 'Team_Member', #lename#)>
<cfset temp = QuerySetCell(myQuery, 'Calls', #all_calls#)>
<cfset temp = QuerySetCell(myQuery, 'Unique', #unique_calls#)>
<cfset temp = QuerySetCell(myQuery, 'Live_Connections', #live_convo#)>
<cfset temp = QuerySetCell(myQuery, 'Rescued_Calls', #rescued#)>
</cfloop>
<!--- The code is running just fine up to this point. I used a cfdump to check the query "pull_staff" and it is returning the right results with correct column names --->
<cfset fastFileWriter = createObject("java", "FastResultsetToFile")>
<cfset fastFileWriter.exportResultsetToFile(myQuery, "#TempFile#", ',', "UTF-8")>
I expect it has something to do with a missing Java dependency on the new server
<cfset fastFileWriter = createObject("java", "FastResultsetToFile")>
For this to work it requires that the FastResultsetToFile class (or related JAR) is in one of the directories that ColdFusion uses for its classpath, otherwise it will never run.
I am experiencing performance issues while writing and merging thousands of PDF files into single PDF file. Each PDF file is about 1.76MB. My JVM heap size is default of 512 only. I've increased the JAVA heap size to 2048 MB. The following code write the pdf form fields for 1000 pdfs and merge the 1000 pdfs as single. More than 1000 pdfs it throws the following error log in coldfusion-out.log file.
Dec 30, 2016 18:43:12 PM Information [scheduler-1] - Run Client Storage Purge
How can I resolve this?
I am using the following code to write some pdf fields and merge as single pdf:
<cfset outputFilePath = "PDF_#dateformat(now(),"dd_mm_yyyy")#">
<cfloop from="1" to="1500" index="i">
<cfset RandToken = createUUID()>
<cfset inputFileName = "Test-cert.pdf">
<cfif directoryExists("C:\ColdFusion10\cfusion\wwwroot\outputPDF\#outputFilePath#") EQ false>
<cfdirectory action="create" directory="C:\ColdFusion10\cfusion\wwwroot\outputPDF\#outputFilePath#">
</cfif>
<cfset OutputFile = "outputPDF/#outputFilePath#/#RandToken#_outputPDF.pdf">
<cfpdfform source="#inputFileName#" destination="#OutputFile#" action="populate">
<cfloop from="1" to="10" index="CurrentField">
<cfset FormField = "BirthDate">
<cfset FormValue = "12/24/1987">
<cfpdfformparam name="#FormField#" value="#FormValue#" />
</cfloop>
<cfloop from="1" to="3" index="Fieldvalue">
<cfset FormField = "fullName">
<cfset WorkingText = "Sathish#Fieldvalue#">
<cfpdfformparam name="#FormField#" value="#WorkingText#" />
</cfloop>
</cfpdfform>
<cfpdf action="write" flatten="yes" overwrite="yes" source="#OutputFile#" destination="#OutputFile#">
</cfloop>
<cfpdf action="merge" directory="C:\ColdFusion10\cfusion\wwwroot\outputPDF\#outputFilePath#" order="name" ascending="yes" stoponerror="false" overwrite="yes" destination="mergedPDf.pdf" />
<cfdirectory action="list" directory="C:\ColdFusion10\cfusion\wwwroot\outputPDF\#outputFilePath#" recurse="yes" name="resultOfZip"/>
<cfloop query="resultOfZip">
<cffile action="delete" file="C:\ColdFusion10\cfusion\wwwroot\outputPDF\#outputFilePath#\#resultOfZip.NAME#">
</cfloop>
<cfheader name="Content-Disposition" value='inline;filename="mergedPDf.pdf"'>
<cfcontent type="application/pdf" file="mergedPDf.pdf" deleteFile="yes">
I am running this above code on the following configuration machine:
windows 10, RAM 6 GB, CF10
Can anyone suggest how I might merge all the files into a single pdf?
I'm working on an application done in Coldfusion 9. I have to migrate it in CF11 and I would like to improve the code. The current application in CF9 is done like this:
Application.cfm:
<cfapplication name="MyApp"
clientManagement="yes"
clientStorage="registry"
setClientCookies="yes"
sessionManagement="yes"
sessionTimeout="#CreateTimeSpan(0,1,0,0)#"
applicationTimeout="#CreateTimeSpan(0,0,2,0)#"
/>
<cfset application.datasource = "MyApp"/>
<cfset application.name = "MyApp"/>
<cfset application.access = "App"/>
<cfset application.version = "1.1"/>
<cfset application.title = "My Application"/>
<cfset application.inc_path = "includes"/>
<cfset application.com_path = "components"/>
<cfset application.scripts_path = "scripts"/>
<cfset application.styles_path = "styles"/>
<cfset application.email = "firstname.lastnane#myapplication.com" />
<cfset application.YEAR = 2016/>
<cfif Not IsDefined("session.language_cd")>
<cfset session.language_cd = "ENG">
</cfif>
<cfset session.email_support_team = "support#myapplication.com" />
<cfinclude template="ui_lib.cfm">
Inside the file "ui_lib.cfm", there are a lot of variables defined and used in all other .cfm files:
<cfswitch expression="#session.ui_lng_cd#">
<cfcase value="FRA">
<cfset ui_lib_abbrev = "Abbréviation" />
<cfset ui_lib_acces = "Accès" />
<cfset ui_lib_active_sans_accent = "Actif" />
</cfcase>
<cfcase value="ENG">
<cfset ui_lib_abbrev = "Abbreviation" />
<cfset ui_lib_acces = "Access" />
<cfset ui_lib_active_sans_accent = "Active" />
</cfcase>
</cfswitch>
For example in menu.cfm:
<div id="menu">
<h5><cfoutput>#session.user#</cfoutput></h5>
<ul>
<li><cfoutput>#ui_lib_abbrev#</cfoutput></li>
<li><cfoutput>#ui_lib_acces#</cfoutput></li>
<li><cfoutput>#ui_lib_active_sans_accent#</cfoutput></li>
</ul>
</div>
I have tried to create an Application.cfc to replace application.cfm:
<cfcomponent displayname="MyApp">
<cfset This.name = "MyApp">
<cfset This.sessionManagement="yes">
<cfset This.clientManagement="no">
<cfset This.loginStorage="session">
<cfset This.sessionTimeout = CreateTimeSpan(0,0,0,1)>
<cfset This.applicationTimeout = CreateTimeSpan(0,0,2,0) >
<cfset This.setClientCookies="no">
<cfset This.domainCookies="yes">
<cfset This.scriptProtect = "All">
<cffunction name="onApplicationStart">
<cfscript>
Application.homePage = "/index.cfm";
Application.datasource = "MyApp";
Application.name = "MyApp";
Application.access = "App";
Application.version = "1.1";
Application.title = "My Application";
Application.inc_path = "includes";
Application.com_path = "components";
Application.scripts_path = "scripts";
Application.styles_path = "styles";
Application.email = "firstname.lastnane#myapplication.com"
Application.YEAR = 2016;
</cfscript>
<cfinclude template="ui_lib.cfm">
</cffunction>
<cffunction name="onSessionStart">
<cfif Not IsDefined("session.language_cd")>
<cfset session.language_cd = "ENG">
</cfif>
<cfif Not IsDefined("session.g_exercice")>
<cfset todayDate = Now()>
<cfset SESSION.g_exercice = #DateFormat(todayDate, "yyyy")#>
</cfif>
<cfif Not IsDefined("session.sec_first_pass")>
<cfset SESSION.sec_first_pass = 0>
</cfif>
<cfset session.email_support_team = "support#myapplication.com" />
</cffunction>
</cfcomponent>
I have created application.cfc and removed application.cfm and tried to run the application. It's ok, but I have Coldfusion errors with the variables defined in ui_lib.cfm. The server says that the variables are not defined. Could you please tell me why and how to solve the problem?
I would like to know if it's better to use a file Application.cfc with the same definitions or keep the current file Application.cfm ?
Thanks in advance for your help.
I've done some cfm to cfc conversions and the answer depends upon the usage. As has been mentioned, session based logic in the application scope won't work.
If there's a way to change the user's language which updates the session.ui_lng_cd value and therefore the language displayed to the user then the easiest answer is to set language variables in the OnRequestStart event. You'll have to change the scope of the variables to the request scope when set and used but hopefully that'll be easy enough with a global search and replace.
Additional notes:
It would also be possible to store those language variables in the session, by placing the code in the OnSessionStart event but generally it's a good idea to keep session storage minimal as if you start storing a lot in session on a busy site it can use up a lot of memory.
Another way to do this that would take more work but I think is more efficient if you have a lot of these would be to create a two level array in the application that stores the language strings and use the session language as the first level of key. This way very little memory is used on each request to old variables.
So in your application.cfc OnApplicationStart you'd have:
application.languageStrings = {};
application.languageStrings["ENG"] = {};
application.languageStrings["ENG"]["ui_lib_abbrev"] = "Abbreviation";
application.languageStrings["ENG"]["ui_lib_acces"] = "Access";
application.languageStrings["ENG"]["ui_lib_active_sans_accent"] = "Active";
application.languageStrings["FRA"] = {};
application.languageStrings["FRA"]["ui_lib_abbrev"] = "Abbréviatio";
application.languageStrings["FRA"]["ui_lib_acces"] = "Accès";
application.languageStrings["FRA"]["ui_lib_active_sans_accent"] = "Actif";
And to output the right string you'd use:
#application.languageStrings[session.language_cd]["ui_lib_active_sans_accent"]#
The variables defined in your UDF are places in the variables scope, but by placing the UDF inside onApplicationStart(), the include happens only the one time instead of every request. I think you've figured that out and have them defined again in the variables scope.
I feel the more appropriate solution would be to place them into the application scope so they're just defined the one time instead of them being redefined on every request.
application.ui = {
"ENG" = {
"abbrev" = "Abbreviation"
, "acces" = "Access"
, "active_sans_accent" = "Active"
}
, "FRA" = {
"abbrev" = "Abbréviation"
, "acces" = "Accès"
, "active_sans_accent" = "Actif"
}
};
Then just update any existing reference like so: #application.ui[session.ui_lng_cd].abbrev#.
If your need to manage translated context grows in the future, take a look at Resource Bundles.
Below is the example of calling API that I got from Provider, I am facing problem converting this code to coldfusion. Any help will be appriciated
var parameters = new List<RegaloPayBillerFieldWithValue>
{
new RegaloPayBillerFieldWithValue
{
Name = "NPE",
Value = "1234567890"
}
};
var preReceipt = client.RegaloPayPreReceipt(accessId: "2FC60D63-9091-4530-BC08-AF0D5742BBF2", billerPublicId: 3, localAmount: 0, billParameters: parameters);
The part where I am facing the problem is the upper part i.e.
var parameters = new List<RegaloPayBillerFieldWithValue>
{
new RegaloPayBillerFieldWithValue
{
Name = "NPE",
Value = "1234567890"
}
};
Two variables here i.e. Name and value are not being posted correctly.Test url is http://regalocashservice.cloudapp.net:8085/RegaloCashService.svc?wsdl
You could write-
<cfset wsdlurl = "http://regalocashservice.cloudapp.net:8085/RegaloCashService.svc?wsdl">
<cfset parameters = StructNew()>
<cfset RegaloPayBillerField = ArrayNew(1)>
<cfset vars = structNew()>
<cfset ArrayAppend(RegaloPayBillerField, {Name="NPE", Value="1234567890"})>
<cfset StructAppend(parameters, {RegaloPayBillerFieldWithValue = RegaloPayBillerField })>
<cfset vars["billerPublicId"] = 2>
<cfset vars["localAmount"] = 0>
<cfset vars["accessId"] = "2FC60D63-9091-4530-BC08-AF0D5742AAF2">
<cfinvoke webservice="#wsdlurl#" method="RegaloPayPreReceipt" returnVariable="res" argumentcollection="#vars#" >
<cfinvokeargument name="billParameters" value="#parameters#"/>
</cfinvoke>
<cfdump var="#res.getResponseCode()#">
var parameters = new List<RegaloPayBillerFieldWithValue>
{
new RegaloPayBillerFieldWithValue
{
Name = "NPE",
Value = "1234567890"
}
};
From the example, and WSDL, it looks like they are just creating an array of structures, which is then passed via a wrapper object ie another structure. I think it should work if you create the array, then wrap it like so:
<cfscript>
// create ArrayOfRegaloPayBillerFieldWithValue wrapper object
parameters = [ {Name="NPE", Value="1234567890"} ];
billParameters = { RegaloPayBillerFieldWithValue=parameters };
// create web service
ws = createObject("webservice", "http://regalocashservice.cloudapp.net:8085/RegaloCashService.svc?wsdl");
// debug
writeDump(ws);
// get result code
result = ws.RegaloPayPreReceipt( "2FC60D63-9091-4530-BC08-AF0D5742AAF2"
, 3 , 0, billParameters );
writeDump(result.getResponseCode());
</cfscript>
Note: the code below was tested in CF 11 Dev Edition environment
<cftry>
<cfset parameters = StructNew()>
<cfset StructAppend(parameters, {Name="NPE", Value="1234567890"})>
<cfinvoke webservice="test" method="RegaloPayPreReceipt" returnVariable="res">
<cfinvokeargument name="accessId" value="REAL_ACCESSID_HERE"/>
<cfinvokeargument name="billerPublicId" value="3"/>
<cfinvokeargument name="localAmount" value="0"/>
<cfinvokeargument name="billParameters" value="#parameters#"/>
</cfinvoke>
<cfdump var="#res#">
<cfcatch type="Any">
<cfdump var="#cfcatch.message#">
</cfcatch>
</cftry>
Web Service "test" is mapped to http://regalocashservice.cloudapp.net:8085/RegaloCashService.svc?wsdl in CF Admin Tool. Here is dump of the object returned org.datacontract.schemas._2004._07.domainclasses_dtos_results.RegaloPayPreReceiptResult
Odd question... My application (coldfusion8/MySQL 5.0.88) runs fine except when a user tries to access it using IE6. This throws the following error:
Element PL_SELLERS is undefined in VARIABLES
I'm having trouble reproducing, as it all browsers I can test (IE8 including) do not throw this error.
I know the problem is in the following snippet:
<cfif Session.reload_user EQ "true" OR ( Len(Session.pricelists) EQ 0 OR Len(Session.pl_sellers) EQ 0)>
<cfquery datasource="#Session.datasource#" name="q_preislisten">
... query ...
</cfquery>
<cfif q_preislisten.recordcount NEQ 0>
<cfset variables.pl_sellers = "">
<cfloop query="q_preislisten">
<cfset variables.pl_sellers = variables.pl_sellers & q_preislisten.iln_verkaeufer & ',';>
</cfloop>
</cfif>
<cfif len(variables.pl_sellers) NEQ 0 )>
<cfset variables.pl_sellers = Left(variables.pl_sellers, len(variables.pl_sellers)-1)>
<cfset Session.pl_sellers = variables.pl_sellers>
<cfset Session.reload_user = "false">
</cfif>
<cfelse>
<cfset variables.pl_sellers = Session.pl_sellers>
</cfif>
So my question:
Under what circumstances can variables.pl_sellers be undefined?
I will move the inital declaration <cfset variables.pl_sellers = ""> outside of the whole if statement, so it will always be at least an empty string. Another reason I can think of the check for len(variables.pl_sellers) being outside of the recordcount-if statement. Are there any other things I'm missing?
Thanks!
If your preislisten.recordcount is 0, then when it checks the next IF block it'll be undefined.
Gotta love IE6! Not really an answer to your question but I would add IsDefined() checks so you can at least handle the error gracefully.
<cfif Session.reload_user EQ "true" OR ( Len(Session.pricelists) EQ 0 OR Len(Session.pl_sellers) EQ 0)>
<cfquery datasource="#Session.datasource#" name="q_preislisten">
... query ...
</cfquery>
<cfif q_preislisten.recordcount NEQ 0>
<cfset variables.pl_sellers = "">
<cfloop query="q_preislisten">
<cfset variables.pl_sellers = variables.pl_sellers & q_preislisten.iln_verkaeufer & ',';>
</cfloop>
</cfif>
<cfif IsDefined("variables.pl_sellers") AND len(variables.pl_sellers) NEQ 0 )>
<cfset variables.pl_sellers = Left(variables.pl_sellers, len(variables.pl_sellers)-1)>
<cfset Session.pl_sellers = variables.pl_sellers>
<cfset Session.reload_user = "false">
<cfelse>
<!--- handle the error here --->
</cfif>
<cfelse>
<cfset variables.pl_sellers = Session.pl_sellers>
</cfif>
As above, if query returns no rows then the.variable does not get created.