Loading Video...
Hide Video monkehTweets ColdFusion Twitter wrapper authenticating multiple user accounts

Managing multiple Twitter users authentication with monkehTweet

Play Video

One of the questions I get asked frequently in regards to the monkehTweet ColdFusion Twitter wrapper is the ability to manage multiple users and their access to Twitter.

In this post, I’ve written a sample application to emulate a user-based system. Once a user has logged in, the application can access this user’s Twitter details and send a post to their stream, updating their status.

Check out the video using the above link (or directly on YouTube) to see it in action. Full code with clear comments is included below, and you can download the entire sample application to enjoy and adapt as you wish to suit your needs.

Multiple User Demo

When dealing with Twitter OAuth calls (especially accessing the restricted data requiring authentication), the user’s token and token secret are required to form the base request and the signature required to cryptographically sign the request.

monkehTweet requires the consumer application’s token and secret values to be sent through in the init() constructor method as the consumer application MUST have these in place to connect to the service provider (in this case Twitter) to be recognised.

However, to communicate on behalf of a specific user, monkehTweet needs to have the user’s token and secret value, which are obtained after successful authentication from the user. These values are required to successfully form the authenticated header, base string and signature needed to send to Twitter in the request.

The main function to note in the example and code is the use of setFinalAccessDetails() method within the monkehTweet component. This function will set the OAuth token, OAuth secret and user account name, assuming you have already obtained them from a method of prior authentication.

login.cfm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<!---
Name: login.cfm
Author: Matt Gifford AKA coldfumonkeh 
		(http://www.mattgifford.co.uk)
Date: 28.01.2011
Copyright 2011 Matt Gifford AKA coldfumonkeh. 
		All rights reserved.
--->
 
<cfif structKeyExists (form,'loginBtn')>
	<cfquery name="rstUserLogin"
			 datasource="#application.datasource#">
		SELECT 
			ID,
			username,
			password
		FROM 
			tblUsers 
		WHERE 
			username = <cfqueryparam 
				    cfsqltype="cf_sql_varchar" 
				    value="#form.username#" />
 
		AND password = <cfqueryparam 
				    cfsqltype="cf_sql_varchar" 
				    value="#form.password#" /> 	
	</cfquery>
 
	<cfif rstUserLogin.recordcount>
		<!---
			Query found a user, so let's set the 
			session values and store the user's previously 
			saved twitter authentication details.
		--->
		<cfset session['isLoggedIn'] 	= true />	
		<cfset session['userID']	= rstUserLogin.ID />
 
		<!---
			Relocate the user back to the index main page.
		--->
		<cflocation url="index.cfm" addtoken="false" />
	</cfif>
 
</cfif>
 
<form name="loginForm" method="post">
 
	<label 	for="username">Username: </label>
	<input 	type="text" 
		name="username" 
		id="username" /><br />
 
	<label 	for="password">Password: </label>
	<input 	type="password" 
		name="password" 
		id="password" /><br />
 
	<input 	type="submit" 
		name="loginBtn" 
		value="Log in" />
 
</form>

 

The login form is purely to access our internal application and to authenticate the user against our own database using non-Twitter account details. If the user exists, their userID value is set in the SESSION scope (required for a database query in the next screen) and they are transferred to the index.cfm page to proceed.

index.cfm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
<!---
Name: index.cfm
Author: Matt Gifford AKA coldfumonkeh 
		(http://www.mattgifford.co.uk)
Date: 28.01.2011
Copyright 2011 Matt Gifford AKA coldfumonkeh. 
			All rights reserved.
--->
 
<cfoutput>
<!---
	Only proceed if the user has successfully 
	logged in to our site.
--->
<cfif session.isLoggedIn>
	<!---
		Use the stored userID after login to 
		check if this user has previously authenticated
		with us and we have their twitter details.
	--->
	<cfif structKeyExists (session,'userID')>
 
		<cfquery name="rstTweetDetails" 
				 datasource="#application.datasource#">
			SELECT 
				ID,
				userID,
				accessToken,
				accessSecret,
				screen_name,
				twitter_userID
			FROM 
				tblTweetAccess 
			WHERE 
				userID = <cfqueryparam 	
                                	cfsqltype="cf_sql_numeric" 
					value="#session.userID#" />	
		</cfquery>
 
		<cfif rstTweetDetails.recordcount>
			<!--- 
				Sweet! It looks as though we have this user's 
				authentication access details from a previous visit. 
				They don't need to authenticate through Twitter anymore.	
 
				Store their access details into the session scope.
			--->
			<cfscript>
				session['accessToken']	=	
					rstTweetDetails.accessToken;
				session['accessSecret']	=	
					rstTweetDetails.accessSecret;
				session['screen_name']	=	
					rstTweetDetails.screen_name;
				WriteOutput('<p>You have already 
				authenticated with Twitter.</p>');       
            </cfscript>
 
			<!---
				Output something to the user 
				so that they can proceed.
			--->
			<a href="post.cfm">Send a post using monkehTweets 
				and see the CFC in action</a>
 
		<cfelse>
			<!---
				They have logged in, but have not authenticated
				through Twitter. We need to send them through 
				the OAuth validation process.
 
				Firstly we need to have the user grant access 
				to our application. We do this (using OAuth) 
				through the getAuthorisation() method.
 
				The callbackURL is optional. If not sent through, 
				Twitter will use the callback URL it has 
				stored for your application.
			--->
			<cfset authStruct = 
			application.objMonkehTweet.getAuthorisation(
				callbackURL='http://[yourdomain]/authorize.cfm'
			) />
 
			<cfif authStruct.success>
				<!---
					Here, the returned information is being 
					set into the session scope.
					You could also store these into a DB 
					(if running an application for multiple users).
				--->
				<cfset session['oAuthToken']		
					= authStruct.token />
				<cfset session['oAuthTokenSecret']	
					= authStruct.token_secret />
			</cfif>
 
			<!--- 
				Now, we need to relocate the user to 
				Twitter to perform the authorisation for us.
			--->
			<p>To continue, please authenticate with Twitter.</p>
			<a href="#authStruct.authURL#">
                                Authenticate to proceed</a>
 
		</cfif>		 
 
	</cfif>
 
</cfif>
 
</cfoutput>

Once the user has logged in, we can then use the stored userID from the SESSION scope to query against the tblTweetAccess table to see if they have already authenticated with Twitter and we have their token details.

If we do have these details, we set the access token, access secret and their Twitter screen name into the session scope, as they will be used in the post.cfm page to set the authentication details using the setFinalAccessDetails() method.

If we do not have these details, the user needs to be sent to Twitter to start the authentication process. They will be transferred to authorize.cfm after they have actioned the authentication (hopefully approving our application and allowing us access to their Twitter stream).

A successful authentication will send an oauth_verifier parameter in the URL query string.

authorize.cfm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<!---
Name: authorize.cfm
Author: Matt Gifford AKA coldfumonkeh 
		(http://www.mattgifford.co.uk)
Date: 28.01.2011
Copyright 2011 Matt Gifford AKA coldfumonkeh. 
		All rights reserved.
--->
 
<!--- Proceed if the user has approved the application. --->
<cfif structKeyExists(URL, 'oauth_verifier')>
 
<cfscript>
	returnData	= application.objMonkehTweet.getAccessToken(  
			requestToken	= 	session.oAuthToken,
			requestSecret	= 	session.oAuthTokenSecret,
			verifier	=	url.oauth_verifier
				);
 
if (returnData.success) {
	/* 
		Save these off to your database against 
		your user so you can access their 
		account in the future.
	*/
	session['accessToken']	= returnData.token;
	session['accessSecret']	= returnData.token_secret;
	session['screen_name']	= returnData.screen_name;
	session['user_id']	= returnData.user_id;
 
	/*
		Insert the details for this user into 
		the database so that we can store the 
		token details for next time.
	*/
	queryService = new query();
	queryService.setDatasource(application.datasource); 
	queryService.setName("insertAuthentication");
	queryService.addParam(	name="userID",			
					value="#session['userID']#",							
					cfsqltype="NUMERIC");
 
	queryService.addParam(	name="accessToken",		
					value="#returnData.token#",			
					cfsqltype="VARCHAR");
 
	queryService.addParam(	name="accessSecret",		
					value="#returnData.token_secret#",	
					cfsqltype="VARCHAR");
 
	queryService.addParam(	name="screen_name",		
					value="#returnData.screen_name#",	
					cfsqltype="VARCHAR");
 
	queryService.addParam(	name="twitter_userID",	
					value="#returnData.user_id#",		
					cfsqltype="NUMERIC");
 
	queryService.setSQL(
	"INSERT INTO 
	tblTweetAccess 
		(
			userID,
			accessToken, 
			accessSecret, 
			screen_name, 
			twitter_userID
		) VALUES (
			:userID,
			:accessToken,
			:accessSecret,
			:screen_name,
			:twitter_userID
		)"
	);
 
	result = queryService.execute();
 
	writeDump(returnData);
 
}
</cfscript>
 
<a href="post.cfm">Send a post using monkehTweets 
	and see the CFC in action</a>
 
<cfelse>
 
	<p>You denied access for the application.</p>
 
</cfif>

Following a successful authentication, the user is sent back to authorize.cfm, and we are able to use monkehTweet to obtain the user’s access token, secret and screen name values, which are again stored into the SESSION scope for use in the action page (post.cfm).

As we now have the user’s access tokens, we dont need to send them to Twitter to authenticate every time we wish to access their account on their behalf. This means we can store their details in the database for future use, using the userID stored in the session scope to create the reference to our specific user record.

post.cfm

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!---
Name: post.cfm
Author: Matt Gifford AKA coldfumonkeh 
		(http://www.mattgifford.co.uk)
Date: 28.01.2011
Copyright 2011 Matt Gifford AKA coldfumonkeh. 
		All rights reserved.
--->
<cfscript>
	/*
		We also need to set the values into the 
		authentication class inside monkehTweets
	*/
	application.objMonkehTweet.setFinalAccessDetails(
			oauthToken		= 	session['accessToken'],
			oauthTokenSecret	=	session['accessSecret'],
			userAccountName		=	session['screen_name']
	);
 
	/* 
		Let's make a test call to update the 
		status of the authenticated user.
		If you are using this for a number of users, 
		you will need to set the details prior to each call
		using the setFinalAccessDetails() method above.
	*/
 
	/* 
		If you are using this purely for a single user, 
		you can set all of the authentication details in
		the init() constructor method when instantiating the application
	*/
	returnData = application.objMonkehTweet.postUpdate(
		"I'm using the awesome ##monkehTweets 
		ColdFusion library from @coldfumonkeh!"
	);
</cfscript>
<cfdump var="#returnData#" 
	label="Returned data from the twitter request" />

 

In the final action page, we obtain the OAuth access token details from the SESSION scope. Of course, you could revise this code to run a query to look up the details within the database for the logged in user instead of storing them in a scope. The choice is yours.

Here, we send the details into the setFinalAccessDetails() method to set them into monkehTweet and to create the correct authentication headers to manage this user’s account on their behalf.

Code Caveat

The code in this example contains a bizarre mix of script and tag-based coding, all forming a fully-functioning but bizarre cocktail of ColdFusion awesomeness. Don’t question it, just go with the flow. It was more of a case that I was playing around with different techniques and options. For example, I dont often use the new Query() method for data transactions, so I took the chance to implement it here just to try something ‘different’.

Variety, much like black pepper, is the spice of life.

Download the code

There you go; a very simple example using monkehTweet to handle multiple user accounts within an application, and storing access details for your users.

The full code, including .sql file to build a dummy database is included in the attached .zip archive for your enjoyment.

 

39 Comments

Leave a Comment
  1. Hi Magnus!

    Thanks for the comment and the kind words. monkehTweet was built with the intention to be as easy to set up and run as possible, so I’m glad it’s showing and people are experiencing that for themselves :)

  2. Hi Matt,

    I’m loving MonkehTweets thus far, it works brilliantly… I’d been working on a very similar system for multiple users before I read this post… It’s all about timing!

    I’m a bit confused about how the setFinalAccessDetails() method works. I understand I have to call it before each API call, but I’m unsure as to where the result is being stored and for how long.
    The system I’m working on will need to be able to post to the Twitter API using an individual user’s details, even after their session has ended. It’s no problem to store their tokens in a database and pull that back for each request, but assuming I have thousands of actions happening for different users at once, is there a locking issue? Is it enough to poll the function on each request?

    Thanks.

    1. Hey Gary

      This comment got lost somewhere in the dashboard, so apologies for only just replying.
      I’m really happy that you’ve found monkehTweets useful :)

      i totally understand the concern with the locking issue. It’s something I’ve been considering addressing for a while, although I havent actually had any feedback from people using the code to confirm if it is actually a problem. Have you found the locking an issue?

      Cheers, Matt

      1. Hi Matt,

        Sorry for the delay – your reply got lost too!

        Thus far I’ve not had a problem, but I’m still in alpha and have only a couple of users playing with the system at a time.
        I want to understand more about what this function actually does with the Twitter API – I’ve found that I can actually make several hits to the API with only one poll to setFinalAccessDetails – as long as I do it within the same CF function.

        What I’ve actually done is create a function that accepts a Twitter ID, pulls the tokens from my database and hits setFinalAccessDetails. I call this function at the beginning of any function that needs to hit the Twitter API to say, post a tweet or whatever – but within that same function I can hit the API a few times without having to re auth.

        So I’m wondering what setFinalAccessDetails is doing – does it store a session on the Twitter domain perhaps? Will it keep the same auth details until it receives another setFinalAccessDetails post?

        It’s all a bit confusing, but it’s working perfectly at the moment, so I guess if it ain’t broke… ;)

        While you’re here (assuming you are) I was wondering if you do anything to deal with errors – currently any errors are just dumped out, which causes me no end of hassle. I need to create some kind of universal response object to deal with success and failure I think, but currently I’m pushing it to the bottom of a long list, as it’s not immediately obvious how I’m going to do that!

      2. Actually, after some experimentation, I think it’s entirely possible that I’m in fact hitting some of these requests unauthenticated… I’m checking RTs mainly and I’m not entirely sure that I’m doing it as the authenticated user.
        Is there any way of checking the headers that Twitter is sending back to see the rate limit? Only the specific rate limit method doesn’t seem to correlate with what I’m actually doing…

        1. Hey Gary –

          thanks for the comments.

          I’m glad you posted this. I’ve had another really helpful dev testing the system who found the same issue due to rate limiting and lack of OAuth headers being sent in some requests.

          I’ve found the issue. and am now working through the component to make necessary changes to all functions that require the fix – luckily there aren’t that many.

          The issue was to do with an incorrect OAuth header being sent that didnt match the URL it was being passed to – this was because some of the functions were appending the query params to the API endpoint.

          I’m also adding in a new argument into every function called ‘checkHeaders’, and if set to true (false by default) it will return the responseHeader from the request instead of the request itself. Useful for checking the headers as you’ve requested, but hopefully it wont be needed too much!

          Thanks for your input. It certainly helped.

          1. Hey Matt,

            Thanks, that’s great news. I’ll look out for the update.
            I’m still unsure as to what setFinalAccessDetails really does though – can you explain? I can’t post without using it, but evidently I can ‘GET’ without being authenticated, so I guess that’s why I can do a few separate things without having to re-auth…
            Is it the case that setFinalAccessDetails will auth me for whatever the next API call is, and then I’ll need to re-auth for subsequent calls?

  3. Matt:

    I know you’ve previously mentioned this component hadn’t been tested against OpenBD. I’m here to report I installed it to run against OpenBD and with a small fix to the generateNonce method in oAuthRequest.cfc, it worked like a champ.

    Your original function:

    What I had to do to get it to work with OpenBD

    For whatever reason, the OpenBD RandRange function didn’t play well with the product of the MAX_VALUE for iMax. I simply replaced that with a sufficiently large number and then specified an algorithm for the RandRange function (which you might be able to ignore but it worked when I used it)…and voila.

    Thank you so very much for this effort. I had beat my head against the wall that was Twitter4J until my skull had attained the roughly equivalent consistency of corn chips suspended in a jello slurry.

    This is much better. :)

    1. Hey Craig!

      Thanks for the comment, and I’m really happy that monkehTweets has helped you and saved you some time :)
      The code for your fix (and the original code you changed) did not come through the filter. Would you mind posting again, replacing any characters with HTML friendly equivalents?
      Or send them to me via the contact form and I can add them into the comment stream.

      Many thanks,

      Matt

      1. Ugh! Didn’t even know my code hadn’t posted til this morning when I got an email saying another comment had been posted to this thread. Let me replace some characters and see if this helps. This is what the method looks like now on OpenBD:

        [cffunction name="generateNonce" access="public" returntype="string" output="false" hint="generate nonce value"]
        [cfset var iMin = 0]
        [cfset var iMax = 1000000000]
        [cfset var sToEncode = generateTimestamp() & RandRange(iMin, iMax, "SHA1PRNG")]
        [cfreturn Hash(sToEncode, "SHA")/]
        [/cffunction]

        Square brackets doing the replacing there.

        1. Hi Craig

          That’s perfect, thank you for the updated function, and for posting it again.

          I’ll add it into the next update of the component!

  4. Hi Matt,

    I’m just not having good luck setting this up – trying to fix this I tried to install the multiple user version of your script, and this is the error I got, running CF8 Enterprise, both on my local machine and my live server (crystaltech):

    Really could use some insights!!

    Element isLoggedIn is undefined in a Java object of type class coldfusion.runtime.MemorySessionScope.

    The error occurred in C:\Users\rogerio\Documents\wwwroot\PUAVault.net\tweets2\Application.cfc: line 59
    57 : login form page (withouth causing a constant loop).
    58 : */
    59 : if(!session['isLoggedIn'] or
    60 : !structKeyExists(session, ‘isLoggedIn’)) {
    61 :

    1. Hi How-To

      This issue is occurring as there appears to be no session variables instantiated, or the scope is non-existent. Can you run the template and append ?reinit=true into the query string, e.g. index.cfm?reinit=true.

      The application.cfc file should be looking for that value (in the onRequestStart function) and if present will re-initialise the application and in doing so re-create the session scope with the values required.

      1. I tired the reinit=true and get the same Element accessToken is undefined in a Java object of type class coldfusion.runtime.MemorySessionScope

        error. Any other ideas?

    2. I had same issue, but needed to uncomment line 37 for reinit to set session.isLoggedIn

      //session.isLoggedIn = false; (uncommented this and worked fine)

  5. Hi Gary –

    The latest release will have fixed the issue where some calles were being made without authentication. They were still legitimate requests, but without the OAuth headers being sent they were being sent through as unauthenticated, and as such the rate limit was set at a maximum of 150 per hour. Now they are going through as authenticated requests with a valid OAuth header, the rate limit has jumped to 350 per hour.

    The setFinalAccessDetails() method has one function which is to store the user’s OAuth token and OAuth secret (as well as their username) into the authDetails.cfc. These details are then called on EVERY request to sign the signature base string and validate the OAuth request.

    The default / demo version of monkehTweet that ships with the download shows the authentication process from start to finish (where a user needs to log in to Twitter and approve your application and grant permission for it to access their account stream). On the final page (post.cfm) setFinalAccessDetails() is called to store their details. If a user has already authenticated and approved your application and you have their OAuth token and secret values stored (as in this example) then you don’t need to run authentication again. You simply need to call the setFinalAccessDetails() method to set their auth details into the component for use when building the header request and signature.

  6. Ok, so it’s storing the details for use when posting to Twitter, but I can’t see those details anywhere in the session or application scope, which is why I’ve been a bit confused. Having read a bit more of your OOP book last night (the stuff about beans and inheritance, I’m a bit new to OOP), I’m thinking perhaps it’s updating an instance of authDetails – so then it uses that object when posting the header to Twitter… What I’m unsure of is how that works with multiple users. I’ve stored their token and secret value in the database and I’m pulling those details out for each request which is all working fine – but if the authDetails instance isn’t session based, then I’m worried that having many users at a time will overwrite the authDetails instance before another function has finished posting to Twitter. In fact even if it *is* session based, if I have a scheduled task firing off multiple threads (which I do) then I could run into issues there too.

    Perhaps I’m worrying for no reason. If each authDetails instance is separate and created when I post to a MT function, presumably this will never be an issue?

    BTW: I’ve updated to the latest version and being able to see the headers is immensely helpful. Thanks.
    Ideally I’d like to see the rate limit come back as part of the structure on each request, but I may have a go at doing that myself. Reason being I can use that to throttle the app depending on the result.

    I’ve noticed though that the ‘getRetweets’ function doesn’t seem to affect the API, although it says in the Twitter docs that it *is* rate limited. Don’t suppose you’d know why that is?

  7. Hello again…

    I can’t seem to find anywhere more appropriate to post this – I’ve found a bug(?) in v 1.2.9.
    Presumably, you primarily use the XML format when making your posts to the Twitter API – however I mostly use JSON. When I get an error, the error handling functionality seems to fail on JSON responses as it appears to be using xmlsearch to find and return the error detail.

    Additionally, I’m finding that it errors out even when using XML as the function is searching for ‘hash/error’ and ‘hash/request’ – neither of which seem to exist in Twitter’s response in my tests. (I’m using the ‘lookUpUser’ function to test.) Looking at the API docs, I can see that it’s supposed to be returning both those keys, but it doesn’t seem to when I give it a try.
    If I change this to look for ‘errors’, then it all seems to work as expected.

    Is this an issue or am I doing something wrong??

  8. Hey Matt, wanted to drop a note on here to share an experience I had today and to perhaps help folks who may run across the same thing. I’ve had an instance of MonkehTweets running on my OpenBD server for some time but starting around 2 weeks ago, it quit working. Now, the piece that used it was an admin function that only I ever saw so I didn’t get around to puzzling it out til today.

    Long, frustrating story short, I was getting an error message of “Failed to validate oauth signature and token” for anytime I tried to instantiate the monkehtweet object and sign in with it. No code changes on my end so I was really stumped for a time.

    Turns out, the system time on my server (which platforms like CF and OpenBD use to set their own time) was off by about 20 minutes. This caused the generateNonce function to fail because it was dependent on the generateTimestamp function…which was pulling a date/time stamp via the java.util.Date function. Called my hosting provider to fix the time and voila, it’s back and running fine.

    Just a heads up to anyone who mysteriously suddenly starts getting such errors where none were happening before and no code has been changed. The hash function in generateNonce is dependent upon an accurate timestamp…and that begins with having an accurate time on the server itself.

    1. Hey Craig

      Thanks for the comment, and thank you also for sharing the issues. You’re right, the authentication (and one of the core features of a successful OAuth transaction) is the timestamp and the nonce values matching to avoid the possibility of request hijacking. I can imagine that stumbling across this issue was a pain, but again thanks for sharing the details – hopefully others can benefit if they ever fall into the same situation.

  9. Hi Mat,

    I am trying to send reply to an existing tweet (status),

    I am calling postUpdate function like this:

    monkehService.postUpdate(status=’Reply status’, format=’json’, in_reply_to_status_id=tweet_id);

    but it is still sending the status as independent status, whats the trick mate?

    Thanks

    Philip

    1. Hi Philip

      When sending the status update as a reply, you need to do two things:

      1) – send the ID of the original status message in the ‘in_reply_to_status_id’ parameter
      2) – send the original author’s username as part of the message, eg @coldfumonkeh

      If you dont include the second point (the username) then the ‘in_reply_to_status_id’ param will be ignored and a standard post will be sent instead.

      I hope that helps. If you ARE already doing this, let me know and I’ll dig a little deeper to see what’s going on.

  10. Matt,

    I tried like this,
    monkehService.postUpdate(status=’@pbedi test reply’, format=’json’, in_reply_to_status_id=126062869283487744); but still it is not adding it to reply, whats wrong in the request?

  11. Hi Matt,

    I have a requirement, I need to offer Twitter like functionality, when user is typing message and he enters @ and starts typing name I would like to do the autocomplete search like it is on Twitter, the getFriendsStatus () method in your cfc returns just first 100 list of users which the logged in user follows. how can I make progressive request using your library?

  12. @Philip

    The lookupUser function may be of help to you. It returns 100 records at a time, but can be used with jQuery / AJAX calls to filter as you type.

    1. Hi Philip

      I ran a test call through monkehTweet in reply to one of your tweets.. here’s the code:

      monkehTweet.postUpdate(status=’@pbedi – the in_reply_to_status_id parameters are working for me. This tweet was sent through monkehTweet using it.’, in_reply_to_status_id=’131036979709214720′);

      This worked and I could see in the response that it was marked as a reply to that specific tweet.

  13. Hello,

    I have a problem running the application that comes with your sdk.

    post.cfm returns an error

    Railo 3.3.1.000 Error (expression)
    file or directory Status: 500 Internal Server Error
    Content-Type: text/html
    500 Internal Server Error not exist

    If I use the search method it returns results.

    Regards

      1. No i can’t send status updates, it gives me this error 500, I installed Coldfusion on the same machine, ran same code and it worked.
        So it must be something related to railo 3, but I can’t find what exactly :(

        1. Same issue. Using 1.2.4, so it’s not the documented request variable thing. Wondering if you ever got this problem resolved…?

        2. @pim @dt @pud –

          Hi all. Thanks for noting the issue.

          I discovered that when I added the postWithMedia method to one of the latest releases that the change in authentication had conflicts with Railo but worked with Adobe CF.

          I fixed the issue, as well as changing some of the default error handling (JSON and XML specific responses) and released the revised package a few days ago.

          I apologise for any inconvenience, and please go and download the latest package from https://github.com/coldfumonkeh/monkehTweets to get your Twitter apps up and running cross-platform. :)

      2. I’m getting the same error with Railo. Here’s more detail:

        file or directory Status: 500 Internal Server Error
        Content-Type: text/html

        500 Internal Server Error not exist

        The Error Occurred in \com\coldfumonkeh\base.cfc: line 251

        249:
        250:
        251:
        252:
        253: <!——>

        1. Looks like this commenting system stripped out the CFML.

          Here are the errors again, with less-than symbols removed

          249: /cfcase>
          250: cfdefaultcase>
          251: cfset arrErrSearch = xmlSearch(arguments.data.FileContent,’hash/error’) />
          252: !— Mr Phipps was here – thanks to David for finding the issue here with CF8.01 —>
          253: !——>

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>