Permalink
Browse files

Committing GSTwitPicEngine.

  • Loading branch information...
0 parents commit afbc554ae72eced5a4987778ffab341572a5da0b @Gurpartap committed Jun 29, 2010
Showing with 379 additions and 0 deletions.
  1. +74 −0 GSTwitPicEngine.h
  2. +231 −0 GSTwitPicEngine.m
  3. +74 −0 README.md
@@ -0,0 +1,74 @@
+//
+// GSTwitPicEngine.h
+// TwitPic Uploader
+//
+// Created by Gurpartap Singh on 19/06/10.
+// Copyright 2010 Gurpartap Singh. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+#import "OAToken.h"
+
+#import "ASIHTTPRequest.h"
+
+
+// Define these API credentials as per your applicationss.
+
+// Get here: http://twitter.com/apps
+#define TWITTER_OAUTH_CONSUMER_KEY kTwitterOAuthConsumerKey
+#define TWITTER_OAUTH_CONSUMER_SECRET kTwitterOAuthConsumerSecret
+
+// Get here: http://dev.twitpic.com/apps/
+#define TWITPIC_API_KEY kTwitPicAPIKey
+
+// TwitPic API Version: http://dev.twitpic.com/docs/
+#define TWITPIC_API_VERSION @"2"
+
+// Enable one of the JSON Parsing libraries that the project has.
+// Disable all to get raw string as response in delegate call to parse yourself.
+#define TWITPIC_USE_YAJL 1
+#define TWITPIC_USE_SBJSON 0
+#define TWITPIC_USE_TOUCHJSON 0
+#define TWITPIC_API_FORMAT @"json"
+
+// Implement XML here if you wish to.
+// #define TWITPIC_USE_LIBXML 0
+// #if TWITPIC_USE_LIBXML
+// #define TWITPIC_API_FORMAT @"xml"
+// #endif
+
+
+@protocol GSTwitPicEngineDelegate
+
+- (void)twitpicDidFinishUpload:(NSDictionary *)response;
+- (void)twitpicDidFailUpload:(NSDictionary *)error;
+
+@end
+
+@class ASINetworkQueue;
+
+@interface GSTwitPicEngine : NSObject <ASIHTTPRequestDelegate, UIWebViewDelegate> {
+ __weak NSObject <GSTwitPicEngineDelegate> *_delegate;
+
+ OAToken *_accessToken;
+
+ ASINetworkQueue *_queue;
+}
+
+@property (retain) ASINetworkQueue *_queue;
+
++ (GSTwitPicEngine *)twitpicEngineWithDelegate:(NSObject *)theDelegate;
+- (GSTwitPicEngine *)initWithDelegate:(NSObject *)theDelegate;
+
+- (void)uploadPicture:(UIImage *)picture;
+- (void)uploadPicture:(UIImage *)picture withMessage:(NSString *)message;
+
+@end
+
+
+@interface GSTwitPicEngine (OAuth)
+
+- (void)setAccessToken:(OAToken *)token;
+
+@end
@@ -0,0 +1,231 @@
+//
+// GSTwitPicEngine.m
+// TwitPic Uploader
+//
+// Created by Gurpartap Singh on 19/06/10.
+// Copyright 2010 Gurpartap Singh. All rights reserved.
+//
+
+#import "GSTwitPicEngine.h"
+
+#if TWITPIC_USE_YAJL
+#import "NSObject+YAJL.h"
+
+#elif TWITPIC_USE_SBJSON
+#import "JSON.h"
+
+#elif TWITPIC_USE_TOUCHJSON
+#import "CJSONDeserializer.h"
+
+// #elif TWITPIC_USE_LIBXML
+// #include <libxml/xmlreader.h>
+#endif
+
+#import "ASIFormDataRequest.h"
+#import "ASINetworkQueue.h"
+
+#import "OAConsumer.h"
+#import "OARequestHeader.h"
+
+@implementation GSTwitPicEngine
+
+@synthesize _queue;
+
++ (GSTwitPicEngine *)twitpicEngineWithDelegate:(NSObject *)theDelegate {
+ return [[[self alloc] initWithDelegate:theDelegate] autorelease];
+}
+
+
+- (GSTwitPicEngine *)initWithDelegate:(NSObject *)delegate {
+ if (self = [super init]) {
+ _delegate = delegate;
+ _queue = [[ASINetworkQueue alloc] init];
+ [_queue setMaxConcurrentOperationCount:1];
+ [_queue setShouldCancelAllRequestsOnFailure:NO];
+ [_queue setDelegate:self];
+ [_queue setRequestDidFinishSelector:@selector(requestFinished:)];
+ [_queue setRequestDidFailSelector:@selector(requestFailed:)];
+ // [_queue setQueueDidFinishSelector:@selector(queueFinished:)];
+ }
+
+ return self;
+}
+
+
+- (void)dealloc {
+ _delegate = nil;
+ [_queue release];
+ [super dealloc];
+}
+
+
+#pragma mark -
+#pragma mark Instance methods
+
+- (BOOL)_isValidDelegateForSelector:(SEL)selector {
+ return ((_delegate != nil) && [_delegate respondsToSelector:selector]);
+}
+
+
+- (void)uploadPicture:(UIImage *)picture {
+ [self uploadPicture:picture withMessage:@""];
+}
+
+
+- (void)uploadPicture:(UIImage *)picture withMessage:(NSString *)message {
+ if ([TWITPIC_API_VERSION isEqualToString:@"1"]) {
+ // TwitPic OAuth.
+ NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://api.twitpic.com/1/upload.%@", TWITPIC_API_FORMAT]];
+
+ ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
+
+ [request addPostValue:TWITPIC_API_KEY forKey:@"key"];
+ [request addPostValue:TWITTER_OAUTH_CONSUMER_KEY forKey:@"consumer_token"];
+ [request addPostValue:TWITTER_OAUTH_CONSUMER_SECRET forKey:@"consumer_secret"];
+ [request addPostValue:[_accessToken key] forKey:@"oauth_token"];
+ [request addPostValue:[_accessToken secret] forKey:@"oauth_secret"];
+ [request addPostValue:message forKey:@"message"];
+ [request addData:UIImageJPEGRepresentation(picture, 0.8) forKey:@"media"];
+
+ request.requestMethod = @"POST";
+
+ [_queue addOperation:request];
+ [_queue go];
+ }
+ else {
+ // Twitter OAuth Echo.
+ NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://api.twitpic.com/2/upload.%@", TWITPIC_API_FORMAT]];
+
+ OAConsumer *consumer = [[[OAConsumer alloc] initWithKey:TWITTER_OAUTH_CONSUMER_KEY secret:TWITTER_OAUTH_CONSUMER_SECRET] autorelease];
+
+ // NSLog(@"consumer: %@", consumer);
+
+ OARequestHeader *requestHeader = [[[OARequestHeader alloc] initWithProvider:@"https://api.twitter.com/1/account/verify_credentials.json"
+ method:@"GET"
+ consumer:consumer
+ token:_accessToken
+ realm:@"http://api.twitter.com/"] autorelease];
+
+ NSString *oauthHeaders = [requestHeader generateRequestHeaders];
+
+ ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
+ [request setUserInfo:[NSDictionary dictionaryWithObject:message forKey:@"message"]];
+
+ [request addRequestHeader:@"X-Verify-Credentials-Authorization" value:oauthHeaders];
+ [request addRequestHeader:@"X-Auth-Service-Provider" value:@"https://api.twitter.com/1/account/verify_credentials.json"];
+
+ [request addPostValue:TWITPIC_API_KEY forKey:@"key"];
+ [request addPostValue:message forKey:@"message"];
+ [request addData:UIImageJPEGRepresentation(picture, 0.8) forKey:@"media"];
+
+ request.requestMethod = @"POST";
+
+ // NSLog(@"requestHeaders: %@", [request requestHeaders]);
+
+ [_queue addOperation:request];
+ [_queue go];
+ }
+}
+
+
+#pragma mark -
+#pragma mark OAuth
+
+- (void)setAccessToken:(OAToken *)token {
+ [_accessToken autorelease];
+ _accessToken = [token retain];
+}
+
+
+#pragma mark -
+#pragma mark ASIHTTPRequestDelegate methods
+
+- (void)requestFinished:(ASIHTTPRequest *)request {
+ // TODO: Pass values as individual parameters to delegate methods instead of wrapping in NSDictionary.
+ NSMutableDictionary *delegateResponse = [[[NSMutableDictionary alloc] init] autorelease];
+
+ [delegateResponse setObject:request forKey:@"request"];
+
+ switch ([request responseStatusCode]) {
+ case 200:
+ {
+ // Success, but let's parse and see.
+ // TODO: Error out if parse failed?
+ // TODO: Need further checks for success.
+ NSDictionary *response = [[NSDictionary alloc] init];
+ NSString *responseString = nil;
+ responseString = [request responseString];
+
+ @try {
+#if TWITPIC_USE_YAJL
+ response = [responseString yajl_JSON];
+#elif TWITPIC_USE_SBJSON
+ response = [responseString JSONValue];
+#elif TWITPIC_USE_TOUCHJSON
+ NSError *error = nil;
+ response = [[CJSONDeserializer deserializer] deserialize:responseString error:&error];
+ if (error != nil) {
+ @throw([NSException exceptionWithName:@"TOUCHJSONParsingException" reason:[error localizedFailureReason] userInfo:[error userInfo]]);
+ }
+// TODO: Implemented XML Parsing.
+// #elif TWITPIC_USE_LIBXML
+#endif
+ }
+ @catch (NSException *e) {
+ NSLog(@"Error while parsing TwitPic response. Does the project really have the parsing library specified? %@.", e);
+ return;
+ }
+
+ [delegateResponse setObject:response forKey:@"parsedResponse"];
+
+ if ([self _isValidDelegateForSelector:@selector(twitpicDidFinishUpload:)]) {
+ [_delegate twitpicDidFinishUpload:delegateResponse];
+ }
+
+ break;
+ }
+ case 400:
+ // Failed.
+ [delegateResponse setObject:@"Bad request. Missing parameters." forKey:@"errorDescription"];
+
+ if ([self _isValidDelegateForSelector:@selector(twitpicDidFailUpload:)]) {
+ [_delegate twitpicDidFailUpload:delegateResponse];
+ }
+
+ break;
+ default:
+ [delegateResponse setObject:@"Request failed." forKey:@"errorDescription"];
+
+ if ([self _isValidDelegateForSelector:@selector(twitpicDidFailUpload:)]) {
+ [_delegate twitpicDidFailUpload:delegateResponse];
+ }
+
+ break;
+ }
+}
+
+
+- (void)requestFailed:(ASIHTTPRequest *)request {
+ NSMutableDictionary *delegateResponse = [[[NSMutableDictionary alloc] init] autorelease];
+
+ [delegateResponse setObject:request forKey:@"request"];
+
+ switch ([request responseStatusCode]) {
+ case 401:
+ // Twitter.com could be down or slow. Or your request took too long to reach twitter.com authentication verification via twitpic.com.
+ // TODO: Attempt to try again?
+ [delegateResponse setObject:@"Timed out verifying authentication token with Twitter.com. This could be a problem with TwitPic servers. Try again later." forKey:@"errorDescription"];
+
+ break;
+ default:
+ [delegateResponse setObject:@"Request failed." forKey:@"errorDescription"];
+ break;
+ }
+
+ if ([self _isValidDelegateForSelector:@selector(twitpicDidFailUpload:)]) {
+ [_delegate twitpicDidFailUpload:delegateResponse];
+ }
+}
+
+
+@end
@@ -0,0 +1,74 @@
+
+GSTwitPicEngine
+=============
+
+GSTwitPicEngine provides easy to implement wrapper around the TwitPic.com's OAuth (v1) and OAuth Echo (v2) API for iPhone application projects.
+
+Requirements
+------------
+
+ * **ASIHTTPRequest** - [http://allseeing-i.com/ASIHTTPRequest/]
+ * **OAuthConsumer** - [http://github.com/jdg/oauthconsumer]
+ * **OARequestHeader** - [http://github.com/Gurpartap/OARequestHeader]
+ * One of these **JSON parsers**:
+ - yajl & yajl-objc (enabled by default) - [http://github.com/gabriel/yajl-objc]
+ - TouchJSON
+ - SBJSON
+ * MGTwitterEngine or anything of your choice that supplies the **OAToken instance** (from OAuthConsumer).
+
+Usage
+-----
+
+ * Set kTwitterOAuthConsumerKey, kTwitterOAuthConsumerSecret and kTwitPicAPIKey constants to their respective values before GSTwitPicEngine.h is imported.
+ * See GSTwitPicEngine.h to configure TwitPic API Format (XML or JSON) and to set which JSON Parser to use.
+ * Add header file:
+
+ #import "GSTwitPicEngine.h"
+ * Setup retained (@synthesize) instance var/property in the header:
+
+ GSTwitPicEngine *twitpicEngine;
+ * Implement **GSTwitPicEngineDelegate** protocol for the class.
+ * Initialize the engine with class or as needed:
+
+ self.twitpicEngine = (GSTwitPicEngine *)[GSTwitPicEngine twitpicEngineWithDelegate:self];
+ * Find the authorization token and supply to twitpicEngine with:
+
+ [twitpicEngine setAccessToken:token];
+ * Then to upload image and attach a text message along with it (does not post to twitter):
+
+ [twitpicEngine uploadPicture:[UIImage imageNamed:@"mypic.png"] withMessage:@"Hello world!"]; // This message is supplied back in success delegate call in request's userInfo.
+ * To upload image only:
+
+ [twitpicEngine uploadPicture:uploadImageView.image];
+* Upon end of request, one of the delegate methods is called with appropriate data and information.
+
+GSTwitPicEngineDelegate
+--------------------------------------
+
+ * GSTwitPicEngineDelegate protocol specifies two delegate methods:
+
+<pre>- (void)twitpicDidFinishUpload:(NSDictionary *)response {
+ NSLog(@"TwitPic finished uploading: %@", response);
+
+ // [response objectForKey:@"parsedResponse"] gives an NSDictionary of the response one of the parsing libraries was available.
+ // Otherwise, use [[response objectForKey:@"request"] objectForKey:@"responseString"] to parse yourself.
+
+ if ([[[response objectForKey:@"request"] userInfo] objectForKey:@"message"] > 0 && [[response objectForKey:@"parsedResponse"] count] > 0) {
+ // Uncomment to update status upon successful upload, using MGTwitterEngine's instance.
+ // [twitterEngine sendUpdate:[NSString stringWithFormat:@"%@ %@", [[[response objectForKey:@"request"] userInfo] objectForKey:@"message"], [[response objectForKey:@"parsedResponse"] objectForKey:@"url"]]];
+ }
+}</pre>
+
+<pre>- (void)twitpicDidFailUpload:(NSDictionary *)error {
+ NSLog(@"TwitPic failed to upload: %@", error);
+
+ if ([[error objectForKey:@"request"] responseStatusCode] == 401) {
+ // UIAlertViewQuick(@"Authentication failed", [error objectForKey:@"errorDescription"], @"OK");
+ }
+}
+</pre>
+
+[http://allseeing-i.com/ASIHTTPRequest/]: http://allseeing-i.com/ASIHTTPRequest/
+[http://github.com/jdg/oauthconsumer]: http://github.com/jdg/oauthconsumer
+[http://github.com/Gurpartap/OARequestHeader]: http://github.com/Gurpartap/OARequestHeader
+[http://github.com/gabriel/yajl-objc]: http://github.com/gabriel/yajl-objc

0 comments on commit afbc554

Please sign in to comment.