Skip to content

Commit

Permalink
Committing GSTwitPicEngine.
Browse files Browse the repository at this point in the history
  • Loading branch information
Gurpartap committed Jun 29, 2010
0 parents commit afbc554
Show file tree
Hide file tree
Showing 3 changed files with 379 additions and 0 deletions.
74 changes: 74 additions & 0 deletions GSTwitPicEngine.h
@@ -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
231 changes: 231 additions & 0 deletions GSTwitPicEngine.m
@@ -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
74 changes: 74 additions & 0 deletions README.md
@@ -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.