Google g suite Invalid Given/Family Name: FamilyName (ColdFusion/HTTP POST) - coldfusion

I have seen several posts about this issue, but I haven't been able to overcome mine using the suggestions. Following is my code and the results:
<cffunction name="CreateUser" hint="Create new GSuite user." returntype="struct" access="public">
<cfargument name="token" hint="The Google-provided access token." type="string" required="yes">
<cfargument name="state" hint="The unique anti-forgery string." type="string" required="yes">
<cfargument name="userdata" hint="A json string containing user data" type="string" required="yes">
<cfargument name="api" hint="API Key for the Google Domain" type="string" required="yes">
<cfhttp method="post" charset="utf-8" url="https://www.googleapis.com/admin/directory/v1/users?state=#state#&access_token=#token#" result="uResult">
<cfhttpparam type="header" name="auth" value="Authorization: Bearer #token#">
<cfhttpparam type="header" name="accept" value="Accept: application/json">
<cfhttpparam type="header" name="content" value="Content-type: application/json">
<cfhttpparam type="body" name="body" value=#userdata#>
</cfhttp>
<cfreturn uResult>
</cffunction>
The JSON string being used is:
{
"password":"Test#me12!",
"primaryEmail":"John#doe.com",
"name":
{
"familyName":"Doe",
"givenName":"John"
}
}
I am taking my HTTP POST structure from the following example:
Google Users: insert (Directory API)
The result I get back from Google is this:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "invalid",
"message": "Invalid Given/Family Name: FamilyName"
}
],
"code": 400,
"message": "Invalid Given/Family Name: FamilyName"
}
}
I cannot understand what might be wrong. Per other posts, I have included the content-type. Per Google's example, I have included the accept header and the auth header. Still, I cannot get a different result.
If I take the JSON string I pass to the function and use it in the Google link above, I am able to create the user. However, if I pass it through HTTP POST, I cannot. Please tell me there is a stray comma or missing dot somewhere in there.

Your header "name" and "values" looks off. Don't put the header names inside the "value" attribute. That's what the "name" attribute is for :-)
For example the authorization and disposition headers should be:
<cfhttpparam type="header" name="Content-Type" value="application/json">
<cfhttpparam type="header" name="Authorization" value="Bearer #token#">
Also, the "body" parameter has no "name" attribute, only a "value":
<cfhttpparam type="body" value="#userdata#">
For more details, see also the cfhttpparam documentation.

Related

EZ Text API & ColdFusion

Anyone have any experience with the EZ Text API and ColdFusion? I'm trying this call:
<cfhttp url="https://app.eztexting.com/sending/messages?format=JSON"
method="POST" result="objGet" charset="utf-8">
<cfhttpparam type="header" name="Content-Type" value="application/x-www-form-urlencoded">
<cfhttpparam type="formfield" name="User" value="xxx" />
<cfhttpparam type="formfield" name="Password" value="xxx"/>
<cfhttpparam type="formfield" name="PhoneNumbers[]" value="9999999999" />
<cfhttpparam type="formfield" name="MessageTypeID" value="1" />
<cfhttpparam type="formfield" name="Message" value="Hello" />
</cfhttp>
... which is returning a status code of 200 and trying to redirect to their home page.
Their tech support can only tell me that I should use curl which is not installed on the server that I need it on. I have used curl successfully in my devel environment, so I'm sure that the url and credentials are good.
Any thoughts are welcome! Thanks.
I'm guessing you're using the REST API. If yes, the reason it's redirecting you to the home page is because the URL is incorrect. Apparently the format parameter is case sensitive. So ?format=JSON should be changed to ?format=json (all lower case).
Making that minor adjustment to your code example:
<cfhttp url="https://app.eztexting.com/sending/messages?format=json"
method="POST" result="objGet" charset="utf-8">
...
</cfhttp>
... returns the expected JSON response for bogus credentials, instead of the html for the home page:
{
"Response": {
"Status": "Failure",
"Code": 401,
"Errors": [
"Authorization Required"
]
}
}
Once you get past this issue, you may want to double check your formfield names. The API lists the parameter name PhoneNumbers, not PhoneNumbers[].

Google Calendar OAuth access_token doesn't work for POST functions

I am having issues calling Calendar:Insert via Google's API
https://www.googleapis.com/calendar/v3/calendars
I don't believe there are authorization/permission issues, the access_token is acquired via a refresh_token with the following scope: "https://www.googleapis.com/auth/calendar"
When I use a valid access_token to perform GET there are no issues, but this is a POST and I consistently get this response:
{"error":
{ "errors":
[{ "domain": "global",
"reason": "authError",
"message": "Invalid Credentials",
"locationType": "header",
"location": "Authorization"
}],
"code": 401,
"message": "Invalid Credentials"
}
}
Here is the Railo code I'm running, I've stripped it of all pretense and nuance:
<cfhttp url="https://www.googleapis.com/calendar/v3/calendars" charset="utf-8" method="post">
<cfhttpparam type="header" name="Authorization" value="bearer #arguments.access_token#" />
<cfhttpparam type="formfield" name="summary" value='hello world' />
</cfhttp>
Here is an example of a get that works just fine:
<cfhttp url="https://www.googleapis.com/calendar/v3/calendars/#arguments.calendarID#/events?access_token=#arguments.access_token#" charset="utf-8" method="get" />
So far I've attempted placing the access_token in a variety of ways. As a query parameter, as a json struct in the cfhttpparam type="body" with no luck
This stackoverflow question indicates that the Google Calendar API documentation neglects to mention a required parameter "minAccessRole". I've fiddled with that too to no avail.
Some time removed from the problem often brings clarity.
With trial and error I was able to get some error code feedback from the API. At some point revealed to me the Content-Type I was sending was "octet-stream".
I added the following line, to specify the Content-Type. I chose "application/json" since the https://developers.google.com/oauthplayground/ had that as the default content-type for the operation: calendar insert.
<cfhttpparam type="header" name="Content-Type" value="application/json" />
Then it occurred to me that I was attempting to send form fields to the API and not JSON.
The final working code for callooks something like this:
<cfhttp url="https://www.googleapis.com/calendar/v3/calendars" charset="utf-8" method="post">
<cfhttpparam type="header" name="Content-Type" value="application/json" />
<cfhttpparam type="header" name="Authorization" value="bearer #arguments.access_token#" />
<cfhttpparam type="body" value='{"summary":"newCalendar"}' />
</cfhttp>

Upload Files To Google Drive Using ColdFusion

*NEW UPDATED FOR BETTER SECOND PART - NOW GETS TO "308 Resume Incomplete", even though file should be just one upload!
I am using the foundation of cfgoogle from Ray Camden. But Google has deprecated the code for document uploads. The new standard is Resumable Media Uploads.
I have this part working (up to and including the "Initiating a resumable upload request") in the above referenced Google document.
Calling Page:
<cfset application.cfc.Google = createObject('component','#path_cf_cfc#Google') />
<cfset application.cfc.GoogleDocs = createObject('component','#path_cf_cfc#GoogleDocs') />
<cfset gtoken = application.cfc.GoogleDocs.authenticate(emailaddress,password)>
<CFSET testdoc = "a\filepath\documentname.doc">
<CFSET FileType = "application/msword">
<CFSET FileTitle = "test_001">
<cfset temp = application.cfc.GoogleDocs.upload_auth("#Application.Map.DocStorage##tv.testdoc#",FileType,FileTitle)>
<CFSET uploadpath = Listgetat(Listgetat(temp.header,ListContains(temp.header,"https://docs.google.com","#chr(10)#"),"#chr(10)#"),2," ") >
<cfset temp2 = application.cfc.GoogleDocs.upload_file("#Application.Map.DocStorage##tv.testdoc#",FileType,FileTitle,uploadpath)>
The code works up to and including the cfset temp line (getting the unique upload URI)
Here is the code for upload_auth:
<cffunction name="upload_auth" access="public" returnType="any" hint="I get a uniqu URI from Google API." output="false">
<cfargument name="myFile" type="string" required="true" hint="filepath to upload.">
<cfargument name="myType" type="string" required="true" hint="application/msword">
<cfargument name="myTitle" type="string" required="true" hint="name of doc">
<cfset GoogleUrl = "https://docs.google.com/feeds/upload/create-session/default/private/full">
<cfset GoogleVersion = 3>
<cfset FileSize = createObject("java","java.io.File").init(myFile).length()>
<cfhttp url="#GoogleUrl#" method="post" result="diditwork" resolveurl="no">
<cfhttpparam type="header" name="Authorization" value="GoogleLogin auth=#getAuth(variables.docservice)#">
<cfhttpparam type="header" name="GData-Version" value="#GoogleVersion#">
<cfhttpparam type="header" name="Content-Length" value="0">
<cfhttpparam type="header" name="X-Upload-Content-Type" value="#myType#">
<cfhttpparam type="header" name="X-Upload-Content-Length" value="#FileSize#">
<cfhttpparam type="header" name="Slug" value="#myTitle#">
</cfhttp>
<cfreturn diditwork>
</cffunction>
OK - So Far So Good.
But here is where it breaks down:
Running upload_file returns "308 Resume Incomplete" (A lest it's not a 400!) from Google. Arrgh!!
Here is the upload_file -
<cffunction name="upload_file" access="public" returnType="any" hint="I upload the document." output="false">
<cfargument name="myFile" type="string" required="true" hint="filepath to upload.">
<cfargument name="myType" type="string" required="true" hint="like application/msword">
<cfargument name="myTitle" type="string" required="true" hint="name of doc">
<cfargument name="myAuthPath" type="string" required="true" hint="call auth">
<cfset FileSize = GetFileInfo(myFile).size >
<CFSET tv.tostartwithzero = FileSize - 1>
<CFFILE action="read" file="#myfile#" variable="FileText">
<cfhttp url="#myAuthPath#" method="put" result="diditwork" resolveurl="no" multipart="yes" charset="utf-8" >
<cfhttpparam type="header" name="Authorization" value="GoogleLogin auth=#getAuth(variables.docservice)#">
<cfhttpparam type="header" name="GData-Version" value="#variables.GoogleVersion#">
<cfhttpparam type="header" name="Content-Length" value="#FileSize#">
<cfhttpparam type="header" name="Content-Range" value="bytes 0-#tv.tostartwithzero#/#FileSize#">
<cfhttpparam type="header" name="Content-Type" value="#myType#">
<cfhttpparam type="body" value="#trim(FileText)#">
</cfhttp>
<cfreturn diditwork>
</cffunction>
So, there we have it - where I am stuck.
I can get the unique URI, but (maybe because it is late at night) I'm brain dead on what I am doing wrong otherwise to complete the file upload.
All help is appreciated.
I strongly recommend taking a different approach here. There are two big issues with the path you're taking:
It appears the code is using the deprecated client login auth mechanism and is using the username/password instead of OAuth.
Using the deprecated documents list API instead of the newer Drive API.
Since you can call java, I'd suggest writing the upload code in plain Java then invoking it from your CF pages as needed.

Upload google docs with coldfusion

I've built a forum-like app in ColdFusion and I want to add a feature with which the users can upload files to Google Docs using their Google accounts and then other users can edit those files.
I've been using this CFC: http://cfgoogle.riaforge.org/ to retrieve Google Docs, but the upload function is currently missing. I need the upload function for the first upload of the file and then for the second part of editing it. I hope that it makes sense.
That's what I'm asking help for. I'm not that experienced with cffunctions and I was wondering if someone could give me a hand with it.
This is what I have so far:
<cffunction name="upload" access="public" returnType="any" hint="I upload the document." output="false">
<cfargument name="myFile" type="string" required="true" hint="file to upload.">
<cfset var result = "">
<cfset var service = variables.docservice>
<cfset theUrl = "https://docs.google.com/feeds/documents/private/full HTTP/1.1">
<cfhttp url="#theURL#" method="post" result="result">
<cfhttpparam type="header" name="Authorization" value="GoogleLogin auth=#getAuth(service)#">
<cfhttpparam type="header" name="Content-Length" value="81047">
<cfhttpparam type="header" name="Content-Type" value="application/msword">
<cfhttpparam type="header" name="Slug" value="#myFile#">
</cfhttp>
<cfreturn result.filecontent>
</cffunction>
But I get the following error when I output the result:
'Invalid request URI'
If someone could help me out with this one (even just show me the way), it would be mostly appreciated.
I would try to expand cfgoogle CFC with upload method using Protocol Guide for uploading.

CFHTTP Content-Length Header for post to Google Voice "API"

Greetings.
I'm trying to send a quick sms through google voice using their existing API. I think the api is what's left from the Grand Central days. They don't have much documentation. Here's where I got my documentation: http://posttopic.com/topic/google-voice-add-on-development
I can authenticate using cfhttp and get the correct response. Then I can get the "_rnr_se" value that is required for request from a google voice command.
When I send over the number, message, and required values (Authorization and _rnr_se), I get a "content-length" is required message from google. But since this is a dynamic post with different form fields, not a file, I'm not sure what to post as the content-length.
If I just put some arbitrary value like "1000" for the content-length, the request just sits there and I never get a response. If I put something like "0" or "500" it comes back with a 500 - "Internal Server Error".
Any ideas on how to get the correct value for content-length before I post?
<cffunction name="submitSMS">
<cfhttp url="https://www.google.com/voice/sms/send/" method="post">
<cfhttpparam type="header" name="Content-Length" value="???">
<cfhttpparam type="header" name="Authorization" value="GoogleLogin auth=#SESSION.GoogleAuth#">
<cfhttpparam name="id" value="" type="formfield">
<cfhttpparam name="phoneNumber" value="+1#params.number#" type="formfield">
<cfhttpparam name="text" value="#params.smsMessage#" type="formfield">
<cfhttpparam name="_rnr_se" value="#SESSION.rnr#" type="formfield">
</cfhttp>
<cfdump var="#cfhttp.FileContent#"><cfabort>
</cffunction>
The better way to do this is to just use the google voice java class here:
http://google-voice-java.googlecode.com