From 022f75f32bba23be287801927b012f25d359b06d Mon Sep 17 00:00:00 2001 From: Justine Gartner Date: Mon, 21 Sep 2015 22:01:20 -0400 Subject: [PATCH 01/29] first commit --- .../TalkinToTheNet.xcodeproj/project.pbxproj | 25 ++- TalkinToTheNet/TalkinToTheNet/APIManager.h | 19 ++ TalkinToTheNet/TalkinToTheNet/APIManager.m | 57 ++++++ .../Base.lproj/LaunchScreen.storyboard | 5 +- .../TalkinToTheNet/Base.lproj/Main.storyboard | 80 ++++++++- .../TalkinToTheNet/VegaNomSearchResult.h | 21 +++ .../TalkinToTheNet/VegaNomSearchResult.m | 13 ++ .../TalkinToTheNet/ViewController.h | 15 -- .../TalkinToTheNet/ViewController.m | 27 --- .../TalkinToTheNet/vegaNomViewController.h | 13 ++ .../TalkinToTheNet/vegaNomViewController.m | 164 ++++++++++++++++++ 11 files changed, 384 insertions(+), 55 deletions(-) create mode 100644 TalkinToTheNet/TalkinToTheNet/APIManager.h create mode 100644 TalkinToTheNet/TalkinToTheNet/APIManager.m create mode 100644 TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.h create mode 100644 TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.m delete mode 100644 TalkinToTheNet/TalkinToTheNet/ViewController.h delete mode 100644 TalkinToTheNet/TalkinToTheNet/ViewController.m create mode 100644 TalkinToTheNet/TalkinToTheNet/vegaNomViewController.h create mode 100644 TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m diff --git a/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj b/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj index ee35a70..fc64322 100644 --- a/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj +++ b/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj @@ -7,21 +7,27 @@ objects = { /* Begin PBXBuildFile section */ + 6BA440E91BB0DB5700BEC68E /* APIManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA440E81BB0DB5700BEC68E /* APIManager.m */; settings = {ASSET_TAGS = (); }; }; + 6BA440EC1BB0DBA700BEC68E /* vegaNomViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA440EB1BB0DBA700BEC68E /* vegaNomViewController.m */; settings = {ASSET_TAGS = (); }; }; + 6BA440F21BB0DF3900BEC68E /* VegaNomSearchResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA440F11BB0DF3900BEC68E /* VegaNomSearchResult.m */; settings = {ASSET_TAGS = (); }; }; 8D7DCD4B1BAF859400A92AD2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D7DCD4A1BAF859400A92AD2 /* main.m */; }; 8D7DCD4E1BAF859400A92AD2 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D7DCD4D1BAF859400A92AD2 /* AppDelegate.m */; }; - 8D7DCD511BAF859400A92AD2 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D7DCD501BAF859400A92AD2 /* ViewController.m */; }; 8D7DCD541BAF859400A92AD2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8D7DCD521BAF859400A92AD2 /* Main.storyboard */; }; 8D7DCD561BAF859400A92AD2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8D7DCD551BAF859400A92AD2 /* Assets.xcassets */; }; 8D7DCD591BAF859400A92AD2 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8D7DCD571BAF859400A92AD2 /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 6BA440E71BB0DB5700BEC68E /* APIManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIManager.h; sourceTree = ""; }; + 6BA440E81BB0DB5700BEC68E /* APIManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APIManager.m; sourceTree = ""; }; + 6BA440EA1BB0DBA700BEC68E /* vegaNomViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vegaNomViewController.h; sourceTree = ""; }; + 6BA440EB1BB0DBA700BEC68E /* vegaNomViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = vegaNomViewController.m; sourceTree = ""; }; + 6BA440F01BB0DF3900BEC68E /* VegaNomSearchResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VegaNomSearchResult.h; sourceTree = ""; }; + 6BA440F11BB0DF3900BEC68E /* VegaNomSearchResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VegaNomSearchResult.m; sourceTree = ""; }; 8D7DCD461BAF859400A92AD2 /* TalkinToTheNet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TalkinToTheNet.app; sourceTree = BUILT_PRODUCTS_DIR; }; 8D7DCD4A1BAF859400A92AD2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 8D7DCD4C1BAF859400A92AD2 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 8D7DCD4D1BAF859400A92AD2 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 8D7DCD4F1BAF859400A92AD2 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; - 8D7DCD501BAF859400A92AD2 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 8D7DCD531BAF859400A92AD2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 8D7DCD551BAF859400A92AD2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 8D7DCD581BAF859400A92AD2 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; @@ -60,8 +66,12 @@ children = ( 8D7DCD4C1BAF859400A92AD2 /* AppDelegate.h */, 8D7DCD4D1BAF859400A92AD2 /* AppDelegate.m */, - 8D7DCD4F1BAF859400A92AD2 /* ViewController.h */, - 8D7DCD501BAF859400A92AD2 /* ViewController.m */, + 6BA440F01BB0DF3900BEC68E /* VegaNomSearchResult.h */, + 6BA440F11BB0DF3900BEC68E /* VegaNomSearchResult.m */, + 6BA440E71BB0DB5700BEC68E /* APIManager.h */, + 6BA440E81BB0DB5700BEC68E /* APIManager.m */, + 6BA440EA1BB0DBA700BEC68E /* vegaNomViewController.h */, + 6BA440EB1BB0DBA700BEC68E /* vegaNomViewController.m */, 8D7DCD521BAF859400A92AD2 /* Main.storyboard */, 8D7DCD551BAF859400A92AD2 /* Assets.xcassets */, 8D7DCD571BAF859400A92AD2 /* LaunchScreen.storyboard */, @@ -149,9 +159,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8D7DCD511BAF859400A92AD2 /* ViewController.m in Sources */, + 6BA440F21BB0DF3900BEC68E /* VegaNomSearchResult.m in Sources */, 8D7DCD4E1BAF859400A92AD2 /* AppDelegate.m in Sources */, 8D7DCD4B1BAF859400A92AD2 /* main.m in Sources */, + 6BA440EC1BB0DBA700BEC68E /* vegaNomViewController.m in Sources */, + 6BA440E91BB0DB5700BEC68E /* APIManager.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -300,6 +312,7 @@ 8D7DCD5F1BAF859400A92AD2 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/TalkinToTheNet/TalkinToTheNet/APIManager.h b/TalkinToTheNet/TalkinToTheNet/APIManager.h new file mode 100644 index 0000000..80c242b --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/APIManager.h @@ -0,0 +1,19 @@ +// +// APIManager.h +// API-Practice +// +// Created by Justine Gartner on 9/20/15. +// Copyright © 2015 Justine Gartner. All rights reserved. +// + +#import +#import + +@interface APIManager : NSObject + ++ (void)GetRequestWithURL: (NSURL *)url + completionHandler: (void(^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler; + ++ (UIImage *)createImageFromString:(NSString *)urlString; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/APIManager.m b/TalkinToTheNet/TalkinToTheNet/APIManager.m new file mode 100644 index 0000000..9b30f56 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/APIManager.m @@ -0,0 +1,57 @@ +// +// APIManager.m +// API-Practice +// +// Created by Justine Gartner on 9/20/15. +// Copyright © 2015 Justine Gartner. All rights reserved. +// + +#import "APIManager.h" + +@implementation APIManager + + +//we make this a class method + +//because the method is stateless. +//this way we don't have to initialize objects to use it + ++ (void)GetRequestWithURL: (NSURL *)url + completionHandler: (void(^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler { + + //CREATING REQUEST: + + //create session + NSURLSession *session = [NSURLSession sharedSession]; + + //create task + NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { + + //NSLog(@"%@", data); + + dispatch_async(dispatch_get_main_queue(), ^{ + + completionHandler(data, response, error); + + }); + }]; + + //PERFORMING REQUEST: + + [task resume]; + +} + ++ (UIImage *)createImageFromString:(NSString *)urlString{ + + NSURL *url = [NSURL URLWithString:urlString]; + + NSData *imageData = [NSData dataWithContentsOfURL:url]; + + UIImage *image = [UIImage imageWithData:imageData]; + + return image; + +} + + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/Base.lproj/LaunchScreen.storyboard b/TalkinToTheNet/TalkinToTheNet/Base.lproj/LaunchScreen.storyboard index 2e721e1..aa08113 100644 --- a/TalkinToTheNet/TalkinToTheNet/Base.lproj/LaunchScreen.storyboard +++ b/TalkinToTheNet/TalkinToTheNet/Base.lproj/LaunchScreen.storyboard @@ -1,7 +1,8 @@ - + - + + diff --git a/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard b/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard index f56d2f3..1bc01ba 100644 --- a/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard +++ b/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard @@ -1,13 +1,14 @@ - + - + + - + - + @@ -15,11 +16,80 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.h b/TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.h new file mode 100644 index 0000000..ceb8cea --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.h @@ -0,0 +1,21 @@ +// +// VegaNomSearchResult.h +// TalkinToTheNet +// +// Created by Justine Gartner on 9/21/15. +// Copyright © 2015 Mike Kavouras. All rights reserved. +// + +#import +#import + +@interface VegaNomSearchResult : NSObject + +@property (nonatomic) NSString *venueName; +@property (nonatomic) NSString *distance; +@property (nonatomic) UIImage *avatar; +@property (nonatomic) NSString *address; +@property (nonatomic) NSString *phoneNumber; +@property (nonatomic) NSString *hoursOfOperation; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.m b/TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.m new file mode 100644 index 0000000..80d3b31 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.m @@ -0,0 +1,13 @@ +// +// VegaNomSearchResult.m +// TalkinToTheNet +// +// Created by Justine Gartner on 9/21/15. +// Copyright © 2015 Mike Kavouras. All rights reserved. +// + +#import "VegaNomSearchResult.h" + +@implementation VegaNomSearchResult + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/ViewController.h b/TalkinToTheNet/TalkinToTheNet/ViewController.h deleted file mode 100644 index 8113a85..0000000 --- a/TalkinToTheNet/TalkinToTheNet/ViewController.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// ViewController.h -// TalkinToTheNet -// -// Created by Michael Kavouras on 9/20/15. -// Copyright © 2015 Mike Kavouras. All rights reserved. -// - -#import - -@interface ViewController : UIViewController - - -@end - diff --git a/TalkinToTheNet/TalkinToTheNet/ViewController.m b/TalkinToTheNet/TalkinToTheNet/ViewController.m deleted file mode 100644 index cbefa29..0000000 --- a/TalkinToTheNet/TalkinToTheNet/ViewController.m +++ /dev/null @@ -1,27 +0,0 @@ -// -// ViewController.m -// TalkinToTheNet -// -// Created by Michael Kavouras on 9/20/15. -// Copyright © 2015 Mike Kavouras. All rights reserved. -// - -#import "ViewController.h" - -@interface ViewController () - -@end - -@implementation ViewController - -- (void)viewDidLoad { - [super viewDidLoad]; - // Do any additional setup after loading the view, typically from a nib. -} - -- (void)didReceiveMemoryWarning { - [super didReceiveMemoryWarning]; - // Dispose of any resources that can be recreated. -} - -@end diff --git a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.h b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.h new file mode 100644 index 0000000..7324e57 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.h @@ -0,0 +1,13 @@ +// +// vegaNomViewController.h +// TalkinToTheNet +// +// Created by Justine Gartner on 9/21/15. +// Copyright © 2015 Mike Kavouras. All rights reserved. +// + +#import + +@interface vegaNomViewController : UIViewController + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m new file mode 100644 index 0000000..77d0ce1 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m @@ -0,0 +1,164 @@ +// +// vegaNomViewController.m +// TalkinToTheNet +// +// Created by Justine Gartner on 9/21/15. +// Copyright © 2015 Mike Kavouras. All rights reserved. +// + +#import "vegaNomViewController.h" +#import "APIManager.h" +#import "VegaNomSearchResult.h" +#import + +#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) + +@interface vegaNomViewController () +@property (weak, nonatomic) IBOutlet UITableView *tableView; +@property (weak, nonatomic) IBOutlet UITextField *whatTextField; +@property (weak, nonatomic) IBOutlet UITextField *whereTextField; +@property (nonatomic) NSMutableArray *searchResults; +@property (nonatomic) CLLocationManager *locationManager; + +@end + +@implementation vegaNomViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.locationManager = [[CLLocationManager alloc] init]; + + self.tableView.delegate = self; + self.tableView.dataSource = self; + self.whatTextField.delegate = self; + self.whereTextField.delegate = self; + self.locationManager.delegate = self; + + [self.locationManager startUpdatingLocation]; + +} + +-(void)makeNewFourSquareRequestWithSearchTerm: (NSString *)searchTerm callbackBlock: (void(^)())block{ + + //searchTerm (comes from our parameter) + + //url(media=music, term=searchterm) + NSString *urlString = [NSString stringWithFormat:@"https://itunes.apple.com/search?media=music&term=%@", searchTerm]; + + //encoded url + NSString *encodedString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; + + NSURL *url = [NSURL URLWithString:encodedString]; + + //make the request + [APIManager GetRequestWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + + if (data != nil) { + + //do something with data + NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; + //NSLog(@"%@", json); + + NSArray *results = [json objectForKey:@"results"]; + + self.searchResults = [[NSMutableArray alloc] init]; + + for (NSDictionary *result in results) { + + NSString *venue = [result objectForKey:@"artistName"]; + NSString *distance = [result objectForKey:@"trackName"]; + NSString *address = [result objectForKey:@"artistName"]; + NSString *phone = [result objectForKey:@"trackName"]; + NSString *hours = [result objectForKey:@"artistName"]; + + NSString *avatarURL = [result objectForKey:@"artworkUrl100"]; + UIImage *avatarImage = [APIManager createImageFromString:avatarURL]; + + VegaNomSearchResult *venueObject = [[VegaNomSearchResult alloc] init]; + + venueObject.venueName = venue; + venueObject.distance = distance; + venueObject.address = address; + venueObject.phoneNumber = phone; + venueObject.hoursOfOperation = hours; + venueObject.avatar = avatarImage; + + [self.searchResults addObject:venueObject]; + + } + + //NSLog(@"%@", self.searchResults); + + //executes the block that we're passing to the method + block(); + } + }]; + +} + +#pragma mark - CLLocationManagerDelegate methods + +- (void)locationManager:(CLLocationManager *)manager + didUpdateLocations:(NSArray *)locations{ + NSLog(@"did update locations"); +} + +-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{ + NSLog(@"did fail with error"); +} + + +#pragma mark - tableViewDatasource methods + +-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ + + return 1; +} + +-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ + + return self.searchResults.count; +} + +-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ + + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"vegaNomCellIdentifier" forIndexPath:indexPath]; + + VegaNomSearchResult *currentResult = self.searchResults[indexPath.row]; + + cell.textLabel.text = currentResult.venueName; + cell.detailTextLabel.text = currentResult.distance; + cell.imageView.image = currentResult.avatar; + + return cell; +} + +#pragma mark - textFieldDelegate methods + +-(BOOL)textFieldShouldReturn:(UITextField *)textField{ + + //dismiss keyboard + [self.view endEditing:YES]; + + //make an api request + [self makeNewFourSquareRequestWithSearchTerm:textField.text callbackBlock:^{ + [self.tableView reloadData]; + }]; + + + return YES; +} + + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end From 8c3014f284ae355f8f9d5d99e9f66040e4efff58 Mon Sep 17 00:00:00 2001 From: Justine Gartner Date: Tue, 22 Sep 2015 00:53:20 -0400 Subject: [PATCH 02/29] set up and working with iTunes API request, need to test CLLocationManagerDelegate --- .../TalkinToTheNet/Base.lproj/Main.storyboard | 11 +++++++++-- TalkinToTheNet/TalkinToTheNet/Info.plist | 5 +++++ TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m | 5 ++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard b/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard index 1bc01ba..7928b5b 100644 --- a/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard +++ b/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard @@ -31,7 +31,7 @@ - + @@ -39,12 +39,19 @@ + diff --git a/TalkinToTheNet/TalkinToTheNet/Info.plist b/TalkinToTheNet/TalkinToTheNet/Info.plist index 6905cc6..db26bc0 100644 --- a/TalkinToTheNet/TalkinToTheNet/Info.plist +++ b/TalkinToTheNet/TalkinToTheNet/Info.plist @@ -2,6 +2,11 @@ + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + CFBundleDevelopmentRegion en CFBundleExecutable diff --git a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m index 77d0ce1..fa660d0 100644 --- a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m +++ b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m @@ -35,7 +35,8 @@ - (void)viewDidLoad { self.whereTextField.delegate = self; self.locationManager.delegate = self; - [self.locationManager startUpdatingLocation]; + //[self.locationManager requestLocation]; + //[self.locationManager startUpdatingLocation]; } @@ -46,6 +47,8 @@ -(void)makeNewFourSquareRequestWithSearchTerm: (NSString *)searchTerm callbackBl //url(media=music, term=searchterm) NSString *urlString = [NSString stringWithFormat:@"https://itunes.apple.com/search?media=music&term=%@", searchTerm]; + //https://api.foursquare.com/v2/venues/explore?ll=40.7,-74&query=vegan&oauth_token=LBLFB0ZHUZAN1SA4RYQUQ4BT0RB11Z03GZ33D0ZXAFTDXSNV&v=20150922 + //encoded url NSString *encodedString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; From 26ed30074d1665e80dd435b858223841ec4f0f0d Mon Sep 17 00:00:00 2001 From: Justine Gartner Date: Wed, 23 Sep 2015 21:03:19 -0400 Subject: [PATCH 03/29] just before implementing the yelp api --- .../TalkinToTheNet.xcodeproj/project.pbxproj | 156 +++++++ .../TalkinToTheNet/Base.lproj/Main.storyboard | 4 +- .../TalkinToTheNet/VegaNomSearchResult.h | 2 +- .../YelpAPISample/NSURLRequest+OAuth.h | 28 ++ .../YelpAPISample/NSURLRequest+OAuth.m | 73 ++++ .../NSMutableURLRequest+Parameters.h | 37 ++ .../NSMutableURLRequest+Parameters.m | 113 +++++ .../Categories/NSString+URLEncoding.h | 35 ++ .../Categories/NSString+URLEncoding.m | 73 ++++ .../OAuthConsumer/Categories/NSURL+Base.h | 34 ++ .../OAuthConsumer/Categories/NSURL+Base.m | 37 ++ .../OAuthConsumer/Crytpo/Base64Transcoder.c | 230 ++++++++++ .../OAuthConsumer/Crytpo/Base64Transcoder.h | 36 ++ .../YelpAPISample/OAuthConsumer/Crytpo/hmac.c | 86 ++++ .../YelpAPISample/OAuthConsumer/Crytpo/hmac.h | 31 ++ .../YelpAPISample/OAuthConsumer/Crytpo/sha1.c | 169 ++++++++ .../YelpAPISample/OAuthConsumer/Crytpo/sha1.h | 14 + .../YelpAPISample/OAuthConsumer/OACall.h | 63 +++ .../YelpAPISample/OAuthConsumer/OACall.m | 168 ++++++++ .../YelpAPISample/OAuthConsumer/OAConsumer.h | 42 ++ .../YelpAPISample/OAuthConsumer/OAConsumer.m | 53 +++ .../OAuthConsumer/OADataFetcher.h | 44 ++ .../OAuthConsumer/OADataFetcher.m | 89 ++++ .../OAHMAC_SHA1SignatureProvider.h | 32 ++ .../OAHMAC_SHA1SignatureProvider.m | 58 +++ .../OAuthConsumer/OAMutableURLRequest.h | 67 +++ .../OAuthConsumer/OAMutableURLRequest.m | 199 +++++++++ .../OAPlaintextSignatureProvider.h | 31 ++ .../OAPlaintextSignatureProvider.m | 40 ++ .../YelpAPISample/OAuthConsumer/OAProblem.h | 53 +++ .../YelpAPISample/OAuthConsumer/OAProblem.m | 165 ++++++++ .../OAuthConsumer/OARequestParameter.h | 48 +++ .../OAuthConsumer/OARequestParameter.m | 72 ++++ .../OAuthConsumer/OAServiceTicket.h | 46 ++ .../OAuthConsumer/OAServiceTicket.m | 51 +++ .../OAuthConsumer/OASignatureProviding.h | 34 ++ .../YelpAPISample/OAuthConsumer/OAToken.h | 72 ++++ .../YelpAPISample/OAuthConsumer/OAToken.m | 328 ++++++++++++++ .../OAuthConsumer/OATokenManager.h | 68 +++ .../OAuthConsumer/OATokenManager.m | 400 ++++++++++++++++++ .../OAuthConsumer/OAuthConsumer.h | 40 ++ .../YelpAPISample/YPAPISample.h | 28 ++ .../YelpAPISample/YPAPISample.m | 102 +++++ .../YelpAPISample/YelpAPISample-Prefix.pch | 10 + .../TalkinToTheNet/YelpAPISample/main.m | 56 +++ .../TalkinToTheNet/vegaNomViewController.m | 73 +++- 46 files changed, 3668 insertions(+), 22 deletions(-) create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/NSURLRequest+OAuth.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/NSURLRequest+OAuth.m create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSMutableURLRequest+Parameters.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSMutableURLRequest+Parameters.m create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSString+URLEncoding.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSString+URLEncoding.m create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSURL+Base.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSURL+Base.m create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/Base64Transcoder.c create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/Base64Transcoder.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/hmac.c create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/hmac.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/sha1.c create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/sha1.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OACall.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OACall.m create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAConsumer.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAConsumer.m create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OADataFetcher.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OADataFetcher.m create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAHMAC_SHA1SignatureProvider.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAHMAC_SHA1SignatureProvider.m create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAMutableURLRequest.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAMutableURLRequest.m create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAPlaintextSignatureProvider.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAPlaintextSignatureProvider.m create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAProblem.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAProblem.m create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OARequestParameter.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OARequestParameter.m create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAServiceTicket.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAServiceTicket.m create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OASignatureProviding.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAToken.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAToken.m create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OATokenManager.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OATokenManager.m create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAuthConsumer.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.h create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.m create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/YelpAPISample-Prefix.pch create mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/main.m diff --git a/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj b/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj index fc64322..5d899cc 100644 --- a/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj +++ b/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj @@ -10,6 +10,26 @@ 6BA440E91BB0DB5700BEC68E /* APIManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA440E81BB0DB5700BEC68E /* APIManager.m */; settings = {ASSET_TAGS = (); }; }; 6BA440EC1BB0DBA700BEC68E /* vegaNomViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA440EB1BB0DBA700BEC68E /* vegaNomViewController.m */; settings = {ASSET_TAGS = (); }; }; 6BA440F21BB0DF3900BEC68E /* VegaNomSearchResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA440F11BB0DF3900BEC68E /* VegaNomSearchResult.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0C71BB37D8A00442479 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C09A1BB37D8A00442479 /* main.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0C81BB37D8A00442479 /* NSURLRequest+OAuth.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C09C1BB37D8A00442479 /* NSURLRequest+OAuth.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0C91BB37D8A00442479 /* NSMutableURLRequest+Parameters.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0A01BB37D8A00442479 /* NSMutableURLRequest+Parameters.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0CA1BB37D8A00442479 /* NSString+URLEncoding.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0A21BB37D8A00442479 /* NSString+URLEncoding.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0CB1BB37D8A00442479 /* NSURL+Base.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0A41BB37D8A00442479 /* NSURL+Base.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0CC1BB37D8A00442479 /* Base64Transcoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0A61BB37D8A00442479 /* Base64Transcoder.c */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0CD1BB37D8A00442479 /* hmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0A81BB37D8A00442479 /* hmac.c */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0CE1BB37D8A00442479 /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0AA1BB37D8A00442479 /* sha1.c */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0CF1BB37D8A00442479 /* OACall.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0AD1BB37D8A00442479 /* OACall.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0D01BB37D8A00442479 /* OAConsumer.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0AF1BB37D8A00442479 /* OAConsumer.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0D11BB37D8A00442479 /* OADataFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0B11BB37D8A00442479 /* OADataFetcher.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0D21BB37D8A00442479 /* OAHMAC_SHA1SignatureProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0B31BB37D8A00442479 /* OAHMAC_SHA1SignatureProvider.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0D31BB37D8A00442479 /* OAMutableURLRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0B51BB37D8A00442479 /* OAMutableURLRequest.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0D41BB37D8A00442479 /* OAPlaintextSignatureProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0B71BB37D8A00442479 /* OAPlaintextSignatureProvider.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0D51BB37D8A00442479 /* OAProblem.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0B91BB37D8A00442479 /* OAProblem.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0D61BB37D8A00442479 /* OARequestParameter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0BB1BB37D8A00442479 /* OARequestParameter.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0D71BB37D8A00442479 /* OAServiceTicket.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0BD1BB37D8A00442479 /* OAServiceTicket.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0D81BB37D8A00442479 /* OAToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0C01BB37D8A00442479 /* OAToken.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0D91BB37D8A00442479 /* OATokenManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0C21BB37D8A00442479 /* OATokenManager.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0DA1BB37D8A00442479 /* YPAPISample.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0C61BB37D8A00442479 /* YPAPISample.m */; settings = {ASSET_TAGS = (); }; }; 8D7DCD4B1BAF859400A92AD2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D7DCD4A1BAF859400A92AD2 /* main.m */; }; 8D7DCD4E1BAF859400A92AD2 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D7DCD4D1BAF859400A92AD2 /* AppDelegate.m */; }; 8D7DCD541BAF859400A92AD2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8D7DCD521BAF859400A92AD2 /* Main.storyboard */; }; @@ -24,6 +44,48 @@ 6BA440EB1BB0DBA700BEC68E /* vegaNomViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = vegaNomViewController.m; sourceTree = ""; }; 6BA440F01BB0DF3900BEC68E /* VegaNomSearchResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VegaNomSearchResult.h; sourceTree = ""; }; 6BA440F11BB0DF3900BEC68E /* VegaNomSearchResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VegaNomSearchResult.m; sourceTree = ""; }; + 6BC1C09A1BB37D8A00442479 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 6BC1C09B1BB37D8A00442479 /* NSURLRequest+OAuth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURLRequest+OAuth.h"; sourceTree = ""; }; + 6BC1C09C1BB37D8A00442479 /* NSURLRequest+OAuth.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURLRequest+OAuth.m"; sourceTree = ""; }; + 6BC1C09F1BB37D8A00442479 /* NSMutableURLRequest+Parameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableURLRequest+Parameters.h"; sourceTree = ""; }; + 6BC1C0A01BB37D8A00442479 /* NSMutableURLRequest+Parameters.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableURLRequest+Parameters.m"; sourceTree = ""; }; + 6BC1C0A11BB37D8A00442479 /* NSString+URLEncoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+URLEncoding.h"; sourceTree = ""; }; + 6BC1C0A21BB37D8A00442479 /* NSString+URLEncoding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+URLEncoding.m"; sourceTree = ""; }; + 6BC1C0A31BB37D8A00442479 /* NSURL+Base.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURL+Base.h"; sourceTree = ""; }; + 6BC1C0A41BB37D8A00442479 /* NSURL+Base.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURL+Base.m"; sourceTree = ""; }; + 6BC1C0A61BB37D8A00442479 /* Base64Transcoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = Base64Transcoder.c; sourceTree = ""; }; + 6BC1C0A71BB37D8A00442479 /* Base64Transcoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Base64Transcoder.h; sourceTree = ""; }; + 6BC1C0A81BB37D8A00442479 /* hmac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = hmac.c; sourceTree = ""; }; + 6BC1C0A91BB37D8A00442479 /* hmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hmac.h; sourceTree = ""; }; + 6BC1C0AA1BB37D8A00442479 /* sha1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sha1.c; sourceTree = ""; }; + 6BC1C0AB1BB37D8A00442479 /* sha1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sha1.h; sourceTree = ""; }; + 6BC1C0AC1BB37D8A00442479 /* OACall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OACall.h; sourceTree = ""; }; + 6BC1C0AD1BB37D8A00442479 /* OACall.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OACall.m; sourceTree = ""; }; + 6BC1C0AE1BB37D8A00442479 /* OAConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAConsumer.h; sourceTree = ""; }; + 6BC1C0AF1BB37D8A00442479 /* OAConsumer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAConsumer.m; sourceTree = ""; }; + 6BC1C0B01BB37D8A00442479 /* OADataFetcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OADataFetcher.h; sourceTree = ""; }; + 6BC1C0B11BB37D8A00442479 /* OADataFetcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OADataFetcher.m; sourceTree = ""; }; + 6BC1C0B21BB37D8A00442479 /* OAHMAC_SHA1SignatureProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAHMAC_SHA1SignatureProvider.h; sourceTree = ""; }; + 6BC1C0B31BB37D8A00442479 /* OAHMAC_SHA1SignatureProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAHMAC_SHA1SignatureProvider.m; sourceTree = ""; }; + 6BC1C0B41BB37D8A00442479 /* OAMutableURLRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAMutableURLRequest.h; sourceTree = ""; }; + 6BC1C0B51BB37D8A00442479 /* OAMutableURLRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAMutableURLRequest.m; sourceTree = ""; }; + 6BC1C0B61BB37D8A00442479 /* OAPlaintextSignatureProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAPlaintextSignatureProvider.h; sourceTree = ""; }; + 6BC1C0B71BB37D8A00442479 /* OAPlaintextSignatureProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAPlaintextSignatureProvider.m; sourceTree = ""; }; + 6BC1C0B81BB37D8A00442479 /* OAProblem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAProblem.h; sourceTree = ""; }; + 6BC1C0B91BB37D8A00442479 /* OAProblem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAProblem.m; sourceTree = ""; }; + 6BC1C0BA1BB37D8A00442479 /* OARequestParameter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OARequestParameter.h; sourceTree = ""; }; + 6BC1C0BB1BB37D8A00442479 /* OARequestParameter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OARequestParameter.m; sourceTree = ""; }; + 6BC1C0BC1BB37D8A00442479 /* OAServiceTicket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAServiceTicket.h; sourceTree = ""; }; + 6BC1C0BD1BB37D8A00442479 /* OAServiceTicket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAServiceTicket.m; sourceTree = ""; }; + 6BC1C0BE1BB37D8A00442479 /* OASignatureProviding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OASignatureProviding.h; sourceTree = ""; }; + 6BC1C0BF1BB37D8A00442479 /* OAToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAToken.h; sourceTree = ""; }; + 6BC1C0C01BB37D8A00442479 /* OAToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OAToken.m; sourceTree = ""; }; + 6BC1C0C11BB37D8A00442479 /* OATokenManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OATokenManager.h; sourceTree = ""; }; + 6BC1C0C21BB37D8A00442479 /* OATokenManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OATokenManager.m; sourceTree = ""; }; + 6BC1C0C31BB37D8A00442479 /* OAuthConsumer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OAuthConsumer.h; sourceTree = ""; }; + 6BC1C0C41BB37D8A00442479 /* YelpAPISample-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "YelpAPISample-Prefix.pch"; sourceTree = ""; }; + 6BC1C0C51BB37D8A00442479 /* YPAPISample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YPAPISample.h; sourceTree = ""; }; + 6BC1C0C61BB37D8A00442479 /* YPAPISample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YPAPISample.m; sourceTree = ""; }; 8D7DCD461BAF859400A92AD2 /* TalkinToTheNet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TalkinToTheNet.app; sourceTree = BUILT_PRODUCTS_DIR; }; 8D7DCD4A1BAF859400A92AD2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 8D7DCD4C1BAF859400A92AD2 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; @@ -45,6 +107,79 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 6BC1C0991BB37D8A00442479 /* YelpAPISample */ = { + isa = PBXGroup; + children = ( + 6BC1C09A1BB37D8A00442479 /* main.m */, + 6BC1C09B1BB37D8A00442479 /* NSURLRequest+OAuth.h */, + 6BC1C09C1BB37D8A00442479 /* NSURLRequest+OAuth.m */, + 6BC1C09D1BB37D8A00442479 /* OAuthConsumer */, + 6BC1C0C41BB37D8A00442479 /* YelpAPISample-Prefix.pch */, + 6BC1C0C51BB37D8A00442479 /* YPAPISample.h */, + 6BC1C0C61BB37D8A00442479 /* YPAPISample.m */, + ); + path = YelpAPISample; + sourceTree = ""; + }; + 6BC1C09D1BB37D8A00442479 /* OAuthConsumer */ = { + isa = PBXGroup; + children = ( + 6BC1C09E1BB37D8A00442479 /* Categories */, + 6BC1C0A51BB37D8A00442479 /* Crytpo */, + 6BC1C0AC1BB37D8A00442479 /* OACall.h */, + 6BC1C0AD1BB37D8A00442479 /* OACall.m */, + 6BC1C0AE1BB37D8A00442479 /* OAConsumer.h */, + 6BC1C0AF1BB37D8A00442479 /* OAConsumer.m */, + 6BC1C0B01BB37D8A00442479 /* OADataFetcher.h */, + 6BC1C0B11BB37D8A00442479 /* OADataFetcher.m */, + 6BC1C0B21BB37D8A00442479 /* OAHMAC_SHA1SignatureProvider.h */, + 6BC1C0B31BB37D8A00442479 /* OAHMAC_SHA1SignatureProvider.m */, + 6BC1C0B41BB37D8A00442479 /* OAMutableURLRequest.h */, + 6BC1C0B51BB37D8A00442479 /* OAMutableURLRequest.m */, + 6BC1C0B61BB37D8A00442479 /* OAPlaintextSignatureProvider.h */, + 6BC1C0B71BB37D8A00442479 /* OAPlaintextSignatureProvider.m */, + 6BC1C0B81BB37D8A00442479 /* OAProblem.h */, + 6BC1C0B91BB37D8A00442479 /* OAProblem.m */, + 6BC1C0BA1BB37D8A00442479 /* OARequestParameter.h */, + 6BC1C0BB1BB37D8A00442479 /* OARequestParameter.m */, + 6BC1C0BC1BB37D8A00442479 /* OAServiceTicket.h */, + 6BC1C0BD1BB37D8A00442479 /* OAServiceTicket.m */, + 6BC1C0BE1BB37D8A00442479 /* OASignatureProviding.h */, + 6BC1C0BF1BB37D8A00442479 /* OAToken.h */, + 6BC1C0C01BB37D8A00442479 /* OAToken.m */, + 6BC1C0C11BB37D8A00442479 /* OATokenManager.h */, + 6BC1C0C21BB37D8A00442479 /* OATokenManager.m */, + 6BC1C0C31BB37D8A00442479 /* OAuthConsumer.h */, + ); + path = OAuthConsumer; + sourceTree = ""; + }; + 6BC1C09E1BB37D8A00442479 /* Categories */ = { + isa = PBXGroup; + children = ( + 6BC1C09F1BB37D8A00442479 /* NSMutableURLRequest+Parameters.h */, + 6BC1C0A01BB37D8A00442479 /* NSMutableURLRequest+Parameters.m */, + 6BC1C0A11BB37D8A00442479 /* NSString+URLEncoding.h */, + 6BC1C0A21BB37D8A00442479 /* NSString+URLEncoding.m */, + 6BC1C0A31BB37D8A00442479 /* NSURL+Base.h */, + 6BC1C0A41BB37D8A00442479 /* NSURL+Base.m */, + ); + path = Categories; + sourceTree = ""; + }; + 6BC1C0A51BB37D8A00442479 /* Crytpo */ = { + isa = PBXGroup; + children = ( + 6BC1C0A61BB37D8A00442479 /* Base64Transcoder.c */, + 6BC1C0A71BB37D8A00442479 /* Base64Transcoder.h */, + 6BC1C0A81BB37D8A00442479 /* hmac.c */, + 6BC1C0A91BB37D8A00442479 /* hmac.h */, + 6BC1C0AA1BB37D8A00442479 /* sha1.c */, + 6BC1C0AB1BB37D8A00442479 /* sha1.h */, + ); + path = Crytpo; + sourceTree = ""; + }; 8D7DCD3D1BAF859400A92AD2 = { isa = PBXGroup; children = ( @@ -64,6 +199,7 @@ 8D7DCD481BAF859400A92AD2 /* TalkinToTheNet */ = { isa = PBXGroup; children = ( + 6BC1C0991BB37D8A00442479 /* YelpAPISample */, 8D7DCD4C1BAF859400A92AD2 /* AppDelegate.h */, 8D7DCD4D1BAF859400A92AD2 /* AppDelegate.m */, 6BA440F01BB0DF3900BEC68E /* VegaNomSearchResult.h */, @@ -159,11 +295,31 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 6BC1C0D31BB37D8A00442479 /* OAMutableURLRequest.m in Sources */, + 6BC1C0DA1BB37D8A00442479 /* YPAPISample.m in Sources */, + 6BC1C0D81BB37D8A00442479 /* OAToken.m in Sources */, + 6BC1C0CE1BB37D8A00442479 /* sha1.c in Sources */, + 6BC1C0D41BB37D8A00442479 /* OAPlaintextSignatureProvider.m in Sources */, + 6BC1C0CD1BB37D8A00442479 /* hmac.c in Sources */, + 6BC1C0CA1BB37D8A00442479 /* NSString+URLEncoding.m in Sources */, + 6BC1C0D71BB37D8A00442479 /* OAServiceTicket.m in Sources */, + 6BC1C0CF1BB37D8A00442479 /* OACall.m in Sources */, 6BA440F21BB0DF3900BEC68E /* VegaNomSearchResult.m in Sources */, + 6BC1C0D61BB37D8A00442479 /* OARequestParameter.m in Sources */, + 6BC1C0D51BB37D8A00442479 /* OAProblem.m in Sources */, + 6BC1C0D11BB37D8A00442479 /* OADataFetcher.m in Sources */, 8D7DCD4E1BAF859400A92AD2 /* AppDelegate.m in Sources */, + 6BC1C0C91BB37D8A00442479 /* NSMutableURLRequest+Parameters.m in Sources */, + 6BC1C0D21BB37D8A00442479 /* OAHMAC_SHA1SignatureProvider.m in Sources */, + 6BC1C0D91BB37D8A00442479 /* OATokenManager.m in Sources */, 8D7DCD4B1BAF859400A92AD2 /* main.m in Sources */, 6BA440EC1BB0DBA700BEC68E /* vegaNomViewController.m in Sources */, + 6BC1C0CC1BB37D8A00442479 /* Base64Transcoder.c in Sources */, + 6BC1C0C71BB37D8A00442479 /* main.m in Sources */, 6BA440E91BB0DB5700BEC68E /* APIManager.m in Sources */, + 6BC1C0D01BB37D8A00442479 /* OAConsumer.m in Sources */, + 6BC1C0C81BB37D8A00442479 /* NSURLRequest+OAuth.m in Sources */, + 6BC1C0CB1BB37D8A00442479 /* NSURL+Base.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard b/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard index 7928b5b..ee89742 100644 --- a/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard +++ b/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard @@ -42,7 +42,7 @@ - + - + diff --git a/TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.h b/TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.h index ceb8cea..cbef4ee 100644 --- a/TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.h +++ b/TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.h @@ -16,6 +16,6 @@ @property (nonatomic) UIImage *avatar; @property (nonatomic) NSString *address; @property (nonatomic) NSString *phoneNumber; -@property (nonatomic) NSString *hoursOfOperation; +@property (nonatomic) NSString *twitterHandle; @end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/NSURLRequest+OAuth.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/NSURLRequest+OAuth.h new file mode 100644 index 0000000..38d1b58 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/NSURLRequest+OAuth.h @@ -0,0 +1,28 @@ +// +// NSURLRequest+OAuth.h +// YelpAPISample +// +// Created by Thibaud Robelain on 7/2/14. +// Copyright (c) 2014 Yelp Inc. All rights reserved. +// + +#import + +@interface NSURLRequest (OAuth) + +/** + @param host The domain host + @param path The path on the domain host + @return Builds a NSURLRequest with all the OAuth headers field set with the host and path given to it. + */ ++ (NSURLRequest *)requestWithHost:(NSString *)host path:(NSString *)path; + +/** + @param host The domain host + @param path The path on the domain host + @param params The query parameters + @return Builds a NSURLRequest with all the OAuth headers field set with the host, path, and query parameters given to it. + */ ++ (NSURLRequest *)requestWithHost:(NSString *)host path:(NSString *)path params:(NSDictionary *)params; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/NSURLRequest+OAuth.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/NSURLRequest+OAuth.m new file mode 100644 index 0000000..9bd61bb --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/NSURLRequest+OAuth.m @@ -0,0 +1,73 @@ +// +// NSURLRequest+OAuth.m +// YelpAPISample +// +// Created by Thibaud Robelain on 7/2/14. +// Copyright (c) 2014 Yelp Inc. All rights reserved. +// + +#import "NSURLRequest+OAuth.h" +#import "OAMutableURLRequest.h" + +/** + OAuth credential placeholders that must be filled by each user in regards to + http://www.yelp.com/developers/getting_started/api_access + */ +#warning Fill in the API keys below with your developer v2 keys. +static NSString * const kConsumerKey = @"E55XCmJCbSrhJ-BtforP4w"; +static NSString * const kConsumerSecret = @"EJrszNNmY8-4t1diOu4FeRu6IyI"; +static NSString * const kToken = @"SV1k-ha9h09pTelPdD9iCtu-0iYp-PEB"; +static NSString * const kTokenSecret = @"cAGd1Lt0bVs7XbTay7X3vsAPCKU"; + +@implementation NSURLRequest (OAuth) + ++ (NSURLRequest *)requestWithHost:(NSString *)host path:(NSString *)path { + return [self requestWithHost:host path:path params:nil]; +} + ++ (NSURLRequest *)requestWithHost:(NSString *)host path:(NSString *)path params:(NSDictionary *)params { + NSURL *URL = [self _URLWithHost:host path:path queryParameters:params]; + + if ([kConsumerKey length] == 0 || [kConsumerSecret length] == 0 || [kToken length] == 0 || [kTokenSecret length] == 0) { + NSLog(@"WARNING: Please enter your api v2 credentials before attempting any API request. You can do so in NSURLRequest+OAuth.m"); + } + + OAConsumer *consumer = [[OAConsumer alloc] initWithKey:kConsumerKey secret:kConsumerSecret]; + OAToken *token = [[OAToken alloc] initWithKey:kToken secret:kTokenSecret]; + + //The signature provider is HMAC-SHA1 by default and the nonce and timestamp are generated in the method + OAMutableURLRequest *request = [[OAMutableURLRequest alloc] initWithURL:URL consumer:consumer token:token realm:nil signatureProvider:nil]; + [request setHTTPMethod:@"GET"]; + [request prepare]; // Attaches our consumer and token credentials to the request + + return request; +} + +#pragma mark - URL Builder Helper + +/** + Builds an NSURL given a host, path and a number of queryParameters + + @param host The domain host of the API + @param path The path of the API after the domain + @param params The query parameters + @return An NSURL built with the specified parameters +*/ ++ (NSURL *)_URLWithHost:(NSString *)host path:(NSString *)path queryParameters:(NSDictionary *)queryParameters { + + NSMutableArray *queryParts = [[NSMutableArray alloc] init]; + for (NSString *key in [queryParameters allKeys]) { + NSString *queryPart = [NSString stringWithFormat:@"%@=%@", key, queryParameters[key]]; + [queryParts addObject:queryPart]; + } + + NSURLComponents *components = [[NSURLComponents alloc] init]; + components.scheme = @"http"; + components.host = host; + components.path = path; + components.query = [queryParts componentsJoinedByString:@"&"]; + + return [components URL]; +} + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSMutableURLRequest+Parameters.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSMutableURLRequest+Parameters.h new file mode 100644 index 0000000..41eb090 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSMutableURLRequest+Parameters.h @@ -0,0 +1,37 @@ +// +// NSMutableURLRequest+Parameters.h +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "OARequestParameter.h" +#import "NSURL+Base.h" + + +@interface NSMutableURLRequest (OAParameterAdditions) + +@property(nonatomic, retain) NSArray *parameters; + +- (void)setHTTPBodyWithString:(NSString *)body; +- (void)attachFileWithName:(NSString *)name filename:(NSString*)filename contentType:(NSString *)contentType data:(NSData*)data; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSMutableURLRequest+Parameters.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSMutableURLRequest+Parameters.m new file mode 100644 index 0000000..2e2fe53 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSMutableURLRequest+Parameters.m @@ -0,0 +1,113 @@ +// +// NSMutableURLRequest+Parameters.m +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "NSMutableURLRequest+Parameters.h" + +static NSString *Boundary = @"-----------------------------------0xCoCoaouTHeBouNDaRy"; + +@implementation NSMutableURLRequest (OAParameterAdditions) + +- (BOOL)isMultipart { + return [[self valueForHTTPHeaderField:@"Content-Type"] hasPrefix:@"multipart/form-data"]; +} + +- (NSArray *)parameters { + NSString *encodedParameters = nil; + + if (![self isMultipart]) { + if ([[self HTTPMethod] isEqualToString:@"GET"] || [[self HTTPMethod] isEqualToString:@"DELETE"]) { + encodedParameters = [[self URL] query]; + } else { + encodedParameters = [[[NSString alloc] initWithData:[self HTTPBody] encoding:NSASCIIStringEncoding] autorelease]; + } + } + + if (encodedParameters == nil || [encodedParameters isEqualToString:@""]) { + return nil; + } +// NSLog(@"raw parameters %@", encodedParameters); + NSArray *encodedParameterPairs = [encodedParameters componentsSeparatedByString:@"&"]; + NSMutableArray *requestParameters = [NSMutableArray arrayWithCapacity:[encodedParameterPairs count]]; + + for (NSString *encodedPair in encodedParameterPairs) { + NSArray *encodedPairElements = [encodedPair componentsSeparatedByString:@"="]; + OARequestParameter *parameter = [[OARequestParameter alloc] initWithName:[[encodedPairElements objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] + value:[[encodedPairElements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; + [requestParameters addObject:parameter]; + [parameter release]; + } + + return requestParameters; +} + +- (void)setParameters:(NSArray *)parameters +{ + NSMutableArray *pairs = [[[NSMutableArray alloc] initWithCapacity:[parameters count]] autorelease]; + for (OARequestParameter *requestParameter in parameters) { + [pairs addObject:[requestParameter URLEncodedNameValuePair]]; + } + + NSString *encodedParameterPairs = [pairs componentsJoinedByString:@"&"]; + + if ([[self HTTPMethod] isEqualToString:@"GET"] || [[self HTTPMethod] isEqualToString:@"DELETE"]) { + [self setURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@", [[self URL] URLStringWithoutQuery], encodedParameterPairs]]]; + } else { + // POST, PUT + [self setHTTPBodyWithString:encodedParameterPairs]; + [self setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; + } +} + +- (void)setHTTPBodyWithString:(NSString *)body { + NSData *bodyData = [body dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; + [self setValue:[NSString stringWithFormat:@"%d", [bodyData length]] forHTTPHeaderField:@"Content-Length"]; + [self setHTTPBody:bodyData]; +} + +- (void)attachFileWithName:(NSString *)name filename:(NSString*)filename contentType:(NSString *)contentType data:(NSData*)data { + + NSArray *parameters = [self parameters]; + [self setValue:[@"multipart/form-data; boundary=" stringByAppendingString:Boundary] forHTTPHeaderField:@"Content-type"]; + + NSMutableData *bodyData = [NSMutableData new]; + for (OARequestParameter *parameter in parameters) { + NSString *param = [NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n", + Boundary, [parameter URLEncodedName], [parameter value]]; + + [bodyData appendData:[param dataUsingEncoding:NSUTF8StringEncoding]]; + } + + NSString *filePrefix = [NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\nContent-Type: %@\r\n\r\n", + Boundary, name, filename, contentType]; + [bodyData appendData:[filePrefix dataUsingEncoding:NSUTF8StringEncoding]]; + [bodyData appendData:data]; + + [bodyData appendData:[[[@"--" stringByAppendingString:Boundary] stringByAppendingString:@"--"] dataUsingEncoding:NSUTF8StringEncoding]]; + [self setValue:[NSString stringWithFormat:@"%d", [bodyData length]] forHTTPHeaderField:@"Content-Length"]; + [self setHTTPBody:bodyData]; + [bodyData release]; +} + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSString+URLEncoding.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSString+URLEncoding.h new file mode 100644 index 0000000..01931ed --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSString+URLEncoding.h @@ -0,0 +1,35 @@ +// +// NSString+URLEncoding.h +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import + + +@interface NSString (OAURLEncodingAdditions) + +- (NSString *)encodedURLString; +- (NSString *)encodedURLParameterString; +- (NSString *)decodedURLString; +- (NSString *)removeQuotes; +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSString+URLEncoding.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSString+URLEncoding.m new file mode 100644 index 0000000..7b9880d --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSString+URLEncoding.m @@ -0,0 +1,73 @@ +// +// NSString+URLEncoding.m +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "NSString+URLEncoding.h" + + +@implementation NSString (OAURLEncodingAdditions) + +- (NSString *)encodedURLString { + NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, + (CFStringRef)self, + NULL, // characters to leave unescaped (NULL = all escaped sequences are replaced) + CFSTR("?=&+"), // legal URL characters to be escaped (NULL = all legal characters are replaced) + kCFStringEncodingUTF8); // encoding + return [result autorelease]; +} + +- (NSString *)encodedURLParameterString { + NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, + (CFStringRef)self, + NULL, + CFSTR(":/=,!$&'()*+;[]@#?"), + kCFStringEncodingUTF8); + return [result autorelease]; +} + +- (NSString *)decodedURLString { + NSString *result = (NSString*)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, + (CFStringRef)self, + CFSTR(""), + kCFStringEncodingUTF8); + + return [result autorelease]; + +} + +-(NSString *)removeQuotes +{ + NSUInteger length = [self length]; + NSString *ret = self; + if ([self characterAtIndex:0] == '"') { + ret = [ret substringFromIndex:1]; + } + if ([self characterAtIndex:length - 1] == '"') { + ret = [ret substringToIndex:length - 2]; + } + + return ret; +} + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSURL+Base.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSURL+Base.h new file mode 100644 index 0000000..5d12b69 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSURL+Base.h @@ -0,0 +1,34 @@ +// +// NSURL+Base.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import + + +@interface NSURL (OABaseAdditions) + +- (NSString *)URLStringWithoutQuery; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSURL+Base.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSURL+Base.m new file mode 100644 index 0000000..3ebe2c6 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Categories/NSURL+Base.m @@ -0,0 +1,37 @@ +// +// NSURL+Base.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "NSURL+Base.h" + + +@implementation NSURL (OABaseAdditions) + +- (NSString *)URLStringWithoutQuery { + NSArray *parts = [[self absoluteString] componentsSeparatedByString:@"?"]; + return [parts objectAtIndex:0]; +} + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/Base64Transcoder.c b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/Base64Transcoder.c new file mode 100644 index 0000000..a655581 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/Base64Transcoder.c @@ -0,0 +1,230 @@ +/* + * Base64Transcoder.c + * Base64Test + * + * Created by Jonathan Wight on Tue Mar 18 2003. + * Copyright (c) 2003 Toxic Software. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include "Base64Transcoder.h" + +#include +#include + +const u_int8_t kBase64EncodeTable[64] = { + /* 0 */ 'A', /* 1 */ 'B', /* 2 */ 'C', /* 3 */ 'D', + /* 4 */ 'E', /* 5 */ 'F', /* 6 */ 'G', /* 7 */ 'H', + /* 8 */ 'I', /* 9 */ 'J', /* 10 */ 'K', /* 11 */ 'L', + /* 12 */ 'M', /* 13 */ 'N', /* 14 */ 'O', /* 15 */ 'P', + /* 16 */ 'Q', /* 17 */ 'R', /* 18 */ 'S', /* 19 */ 'T', + /* 20 */ 'U', /* 21 */ 'V', /* 22 */ 'W', /* 23 */ 'X', + /* 24 */ 'Y', /* 25 */ 'Z', /* 26 */ 'a', /* 27 */ 'b', + /* 28 */ 'c', /* 29 */ 'd', /* 30 */ 'e', /* 31 */ 'f', + /* 32 */ 'g', /* 33 */ 'h', /* 34 */ 'i', /* 35 */ 'j', + /* 36 */ 'k', /* 37 */ 'l', /* 38 */ 'm', /* 39 */ 'n', + /* 40 */ 'o', /* 41 */ 'p', /* 42 */ 'q', /* 43 */ 'r', + /* 44 */ 's', /* 45 */ 't', /* 46 */ 'u', /* 47 */ 'v', + /* 48 */ 'w', /* 49 */ 'x', /* 50 */ 'y', /* 51 */ 'z', + /* 52 */ '0', /* 53 */ '1', /* 54 */ '2', /* 55 */ '3', + /* 56 */ '4', /* 57 */ '5', /* 58 */ '6', /* 59 */ '7', + /* 60 */ '8', /* 61 */ '9', /* 62 */ '+', /* 63 */ '/' +}; + +/* +-1 = Base64 end of data marker. +-2 = White space (tabs, cr, lf, space) +-3 = Noise (all non whitespace, non-base64 characters) +-4 = Dangerous noise +-5 = Illegal noise (null byte) +*/ + +const int8_t kBase64DecodeTable[128] = { + /* 0x00 */ -5, /* 0x01 */ -3, /* 0x02 */ -3, /* 0x03 */ -3, + /* 0x04 */ -3, /* 0x05 */ -3, /* 0x06 */ -3, /* 0x07 */ -3, + /* 0x08 */ -3, /* 0x09 */ -2, /* 0x0a */ -2, /* 0x0b */ -2, + /* 0x0c */ -2, /* 0x0d */ -2, /* 0x0e */ -3, /* 0x0f */ -3, + /* 0x10 */ -3, /* 0x11 */ -3, /* 0x12 */ -3, /* 0x13 */ -3, + /* 0x14 */ -3, /* 0x15 */ -3, /* 0x16 */ -3, /* 0x17 */ -3, + /* 0x18 */ -3, /* 0x19 */ -3, /* 0x1a */ -3, /* 0x1b */ -3, + /* 0x1c */ -3, /* 0x1d */ -3, /* 0x1e */ -3, /* 0x1f */ -3, + /* ' ' */ -2, /* '!' */ -3, /* '"' */ -3, /* '#' */ -3, + /* '$' */ -3, /* '%' */ -3, /* '&' */ -3, /* ''' */ -3, + /* '(' */ -3, /* ')' */ -3, /* '*' */ -3, /* '+' */ 62, + /* ',' */ -3, /* '-' */ -3, /* '.' */ -3, /* '/' */ 63, + /* '0' */ 52, /* '1' */ 53, /* '2' */ 54, /* '3' */ 55, + /* '4' */ 56, /* '5' */ 57, /* '6' */ 58, /* '7' */ 59, + /* '8' */ 60, /* '9' */ 61, /* ':' */ -3, /* ';' */ -3, + /* '<' */ -3, /* '=' */ -1, /* '>' */ -3, /* '?' */ -3, + /* '@' */ -3, /* 'A' */ 0, /* 'B' */ 1, /* 'C' */ 2, + /* 'D' */ 3, /* 'E' */ 4, /* 'F' */ 5, /* 'G' */ 6, + /* 'H' */ 7, /* 'I' */ 8, /* 'J' */ 9, /* 'K' */ 10, + /* 'L' */ 11, /* 'M' */ 12, /* 'N' */ 13, /* 'O' */ 14, + /* 'P' */ 15, /* 'Q' */ 16, /* 'R' */ 17, /* 'S' */ 18, + /* 'T' */ 19, /* 'U' */ 20, /* 'V' */ 21, /* 'W' */ 22, + /* 'X' */ 23, /* 'Y' */ 24, /* 'Z' */ 25, /* '[' */ -3, + /* '\' */ -3, /* ']' */ -3, /* '^' */ -3, /* '_' */ -3, + /* '`' */ -3, /* 'a' */ 26, /* 'b' */ 27, /* 'c' */ 28, + /* 'd' */ 29, /* 'e' */ 30, /* 'f' */ 31, /* 'g' */ 32, + /* 'h' */ 33, /* 'i' */ 34, /* 'j' */ 35, /* 'k' */ 36, + /* 'l' */ 37, /* 'm' */ 38, /* 'n' */ 39, /* 'o' */ 40, + /* 'p' */ 41, /* 'q' */ 42, /* 'r' */ 43, /* 's' */ 44, + /* 't' */ 45, /* 'u' */ 46, /* 'v' */ 47, /* 'w' */ 48, + /* 'x' */ 49, /* 'y' */ 50, /* 'z' */ 51, /* '{' */ -3, + /* '|' */ -3, /* '}' */ -3, /* '~' */ -3, /* 0x7f */ -3 +}; + +const u_int8_t kBits_00000011 = 0x03; +const u_int8_t kBits_00001111 = 0x0F; +const u_int8_t kBits_00110000 = 0x30; +const u_int8_t kBits_00111100 = 0x3C; +const u_int8_t kBits_00111111 = 0x3F; +const u_int8_t kBits_11000000 = 0xC0; +const u_int8_t kBits_11110000 = 0xF0; +const u_int8_t kBits_11111100 = 0xFC; + +size_t EstimateBas64EncodedDataSize(size_t inDataSize) +{ +size_t theEncodedDataSize = (int)ceil(inDataSize / 3.0) * 4; +theEncodedDataSize = theEncodedDataSize / 72 * 74 + theEncodedDataSize % 72; +return(theEncodedDataSize); +} + +size_t EstimateBas64DecodedDataSize(size_t inDataSize) +{ +size_t theDecodedDataSize = (int)ceil(inDataSize / 4.0) * 3; +//theDecodedDataSize = theDecodedDataSize / 72 * 74 + theDecodedDataSize % 72; +return(theDecodedDataSize); +} + +bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize) +{ +size_t theEncodedDataSize = EstimateBas64EncodedDataSize(inInputDataSize); +if (*ioOutputDataSize < theEncodedDataSize) + return(false); +*ioOutputDataSize = theEncodedDataSize; +const u_int8_t *theInPtr = (const u_int8_t *)inInputData; +u_int32_t theInIndex = 0, theOutIndex = 0; +for (; theInIndex < (inInputDataSize / 3) * 3; theInIndex += 3) + { + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (theInPtr[theInIndex + 2] & kBits_11000000) >> 6]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 2] & kBits_00111111) >> 0]; + if (theOutIndex % 74 == 72) + { + outOutputData[theOutIndex++] = '\r'; + outOutputData[theOutIndex++] = '\n'; + } + } +const size_t theRemainingBytes = inInputDataSize - theInIndex; +if (theRemainingBytes == 1) + { + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (0 & kBits_11110000) >> 4]; + outOutputData[theOutIndex++] = '='; + outOutputData[theOutIndex++] = '='; + if (theOutIndex % 74 == 72) + { + outOutputData[theOutIndex++] = '\r'; + outOutputData[theOutIndex++] = '\n'; + } + } +else if (theRemainingBytes == 2) + { + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_11111100) >> 2]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex] & kBits_00000011) << 4 | (theInPtr[theInIndex + 1] & kBits_11110000) >> 4]; + outOutputData[theOutIndex++] = kBase64EncodeTable[(theInPtr[theInIndex + 1] & kBits_00001111) << 2 | (0 & kBits_11000000) >> 6]; + outOutputData[theOutIndex++] = '='; + if (theOutIndex % 74 == 72) + { + outOutputData[theOutIndex++] = '\r'; + outOutputData[theOutIndex++] = '\n'; + } + } +return(true); +} + +bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize) +{ +memset(ioOutputData, '.', *ioOutputDataSize); + +size_t theDecodedDataSize = EstimateBas64DecodedDataSize(inInputDataSize); +if (*ioOutputDataSize < theDecodedDataSize) + return(false); +*ioOutputDataSize = 0; +const u_int8_t *theInPtr = (const u_int8_t *)inInputData; +u_int8_t *theOutPtr = (u_int8_t *)ioOutputData; +size_t theInIndex = 0, theOutIndex = 0; +u_int8_t theOutputOctet; +size_t theSequence = 0; +for (; theInIndex < inInputDataSize; ) + { + int8_t theSextet = 0; + + int8_t theCurrentInputOctet = theInPtr[theInIndex]; + theSextet = kBase64DecodeTable[theCurrentInputOctet]; + if (theSextet == -1) + break; + while (theSextet == -2) + { + theCurrentInputOctet = theInPtr[++theInIndex]; + theSextet = kBase64DecodeTable[theCurrentInputOctet]; + } + while (theSextet == -3) + { + theCurrentInputOctet = theInPtr[++theInIndex]; + theSextet = kBase64DecodeTable[theCurrentInputOctet]; + } + if (theSequence == 0) + { + theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 2 & kBits_11111100; + } + else if (theSequence == 1) + { + theOutputOctet |= (theSextet >- 0 ? theSextet : 0) >> 4 & kBits_00000011; + theOutPtr[theOutIndex++] = theOutputOctet; + } + else if (theSequence == 2) + { + theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 4 & kBits_11110000; + } + else if (theSequence == 3) + { + theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 2 & kBits_00001111; + theOutPtr[theOutIndex++] = theOutputOctet; + } + else if (theSequence == 4) + { + theOutputOctet = (theSextet >= 0 ? theSextet : 0) << 6 & kBits_11000000; + } + else if (theSequence == 5) + { + theOutputOctet |= (theSextet >= 0 ? theSextet : 0) >> 0 & kBits_00111111; + theOutPtr[theOutIndex++] = theOutputOctet; + } + theSequence = (theSequence + 1) % 6; + if (theSequence != 2 && theSequence != 4) + theInIndex++; + } +*ioOutputDataSize = theOutIndex; +return(true); +} diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/Base64Transcoder.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/Base64Transcoder.h new file mode 100644 index 0000000..8752098 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/Base64Transcoder.h @@ -0,0 +1,36 @@ +/* + * Base64Transcoder.h + * Base64Test + * + * Created by Jonathan Wight on Tue Mar 18 2003. + * Copyright (c) 2003 Toxic Software. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#include +#include + +extern size_t EstimateBas64EncodedDataSize(size_t inDataSize); +extern size_t EstimateBas64DecodedDataSize(size_t inDataSize); + +extern bool Base64EncodeData(const void *inInputData, size_t inInputDataSize, char *outOutputData, size_t *ioOutputDataSize); +extern bool Base64DecodeData(const void *inInputData, size_t inInputDataSize, void *ioOutputData, size_t *ioOutputDataSize); + diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/hmac.c b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/hmac.c new file mode 100644 index 0000000..ea511b2 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/hmac.c @@ -0,0 +1,86 @@ +// +// hmac.c +// OAuthConsumer +// +// Created by Jonathan Wight on 4/8/8. +// Copyright 2008 Jonathan Wight. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/* + * Implementation of HMAC-SHA1. Adapted from example at http://tools.ietf.org/html/rfc2104 + + */ + +#include "sha1.h" + +#include +#include + +void hmac_sha1(const u_int8_t *inText, size_t inTextLength, u_int8_t* inKey, size_t inKeyLength, u_int8_t *outDigest) +{ +#define B 64 +#define L 20 + +SHA1_CTX theSHA1Context; +u_int8_t k_ipad[B + 1]; /* inner padding - key XORd with ipad */ +u_int8_t k_opad[B + 1]; /* outer padding - key XORd with opad */ + +/* if key is longer than 64 bytes reset it to key=SHA1 (key) */ +if (inKeyLength > B) + { + SHA1Init(&theSHA1Context); + SHA1Update(&theSHA1Context, inKey, inKeyLength); + SHA1Final(inKey, &theSHA1Context); + inKeyLength = L; + } + +/* start out by storing key in pads */ +memset(k_ipad, 0, sizeof k_ipad); +memset(k_opad, 0, sizeof k_opad); +memcpy(k_ipad, inKey, inKeyLength); +memcpy(k_opad, inKey, inKeyLength); + +/* XOR key with ipad and opad values */ +int i; +for (i = 0; i < B; i++) + { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + +/* +* perform inner SHA1 +*/ +SHA1Init(&theSHA1Context); /* init context for 1st pass */ +SHA1Update(&theSHA1Context, k_ipad, B); /* start with inner pad */ +SHA1Update(&theSHA1Context, (u_int8_t *)inText, inTextLength); /* then text of datagram */ +SHA1Final((u_int8_t *)outDigest, &theSHA1Context); /* finish up 1st pass */ + +/* +* perform outer SHA1 +*/ +SHA1Init(&theSHA1Context); /* init context for 2nd +* pass */ +SHA1Update(&theSHA1Context, k_opad, B); /* start with outer pad */ +SHA1Update(&theSHA1Context, (u_int8_t *)outDigest, L); /* then results of 1st +* hash */ +SHA1Final((u_int8_t *)outDigest, &theSHA1Context); /* finish up 2nd pass */ + +} \ No newline at end of file diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/hmac.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/hmac.h new file mode 100644 index 0000000..67530ba --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/hmac.h @@ -0,0 +1,31 @@ +// +// hmac.h +// OAuthConsumer +// +// Created by Jonathan Wight on 4/8/8. +// Copyright 2008 Jonathan Wight. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef HMAC_H +#define HMAC_H 1 + +extern void hmac_sha1(const u_int8_t *inText, size_t inTextLength, u_int8_t* inKey, const size_t inKeyLength, u_int8_t *outDigest); + +#endif /* HMAC_H */ \ No newline at end of file diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/sha1.c b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/sha1.c new file mode 100644 index 0000000..54dd2fa --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/sha1.c @@ -0,0 +1,169 @@ +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define LITTLE_ENDIAN * This should be #define'd if true. */ +#if __LITTLE_ENDIAN__ +#define LITTLE_ENDIAN +#endif +/* #define SHA1HANDSOFF * Copies data before messing with it. */ + +#include +#include + +#include "sha1.h" + +void SHA1Transform(u_int32_t state[5], u_int8_t buffer[64]); + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#ifdef LITTLE_ENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#else +#define blk0(i) block->l[i] +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void SHA1Transform(u_int32_t state[5], u_int8_t buffer[64]) +{ +u_int32_t a, b, c, d, e; +typedef union { + u_int8_t c[64]; + u_int32_t l[16]; +} CHAR64LONG16; +CHAR64LONG16* block; +#ifdef SHA1HANDSOFF +static u_int8_t workspace[64]; + block = (CHAR64LONG16*)workspace; + memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16*)buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +} + + +/* SHA1Init - Initialize new context */ + +void SHA1Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +void SHA1Update(SHA1_CTX* context, u_int8_t* data, unsigned int len) +{ +unsigned int i, j; + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ + +void SHA1Final(u_int8_t digest[20], SHA1_CTX* context) +{ +u_int32_t i, j; +u_int8_t finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (u_int8_t)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + SHA1Update(context, (u_int8_t *)"\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1Update(context, (u_int8_t *)"\0", 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) { + digest[i] = (u_int8_t) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + /* Wipe variables */ + i = j = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(&finalcount, 0, 8); +#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ + SHA1Transform(context->state, context->buffer); +#endif +} diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/sha1.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/sha1.h new file mode 100644 index 0000000..76f7051 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/Crytpo/sha1.h @@ -0,0 +1,14 @@ + +// From http://www.mirrors.wiretapped.net/security/cryptography/hashes/sha1/sha1.c + +#include + +typedef struct { + u_int32_t state[5]; + u_int32_t count[2]; + u_int8_t buffer[64]; +} SHA1_CTX; + +extern void SHA1Init(SHA1_CTX* context); +extern void SHA1Update(SHA1_CTX* context, u_int8_t* data, u_int32_t len); +extern void SHA1Final(u_int8_t digest[20], SHA1_CTX* context); diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OACall.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OACall.h new file mode 100644 index 0000000..92c6ffa --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OACall.h @@ -0,0 +1,63 @@ +// +// OACall.h +// OAuthConsumer +// +// Created by Alberto García Hierro on 04/09/08. +// Copyright 2008 Alberto García Hierro. All rights reserved. +// bynotes.com + +#import + +@class OAProblem; +@class OACall; + +@protocol OACallDelegate + +- (void)call:(OACall *)call failedWithError:(NSError *)error; +- (void)call:(OACall *)call failedWithProblem:(OAProblem *)problem; + +@end + +@class OAConsumer; +@class OAToken; +@class OADataFetcher; +@class OAMutableURLRequest; +@class OAServiceTicket; + +@interface OACall : NSObject { + NSURL *url; + NSString *method; + NSArray *parameters; + NSDictionary *files; + NSObject *delegate; + SEL finishedSelector; + OADataFetcher *fetcher; + OAMutableURLRequest *request; + OAServiceTicket *ticket; +} + +@property(readonly) NSURL *url; +@property(readonly) NSString *method; +@property(readonly) NSArray *parameters; +@property(readonly) NSDictionary *files; +@property(nonatomic, retain) OAServiceTicket *ticket; + +- (id)init; +- (id)initWithURL:(NSURL *)aURL; +- (id)initWithURL:(NSURL *)aURL method:(NSString *)aMethod; +- (id)initWithURL:(NSURL *)aURL parameters:(NSArray *)theParameters; +- (id)initWithURL:(NSURL *)aURL method:(NSString *)aMethod parameters:(NSArray *)theParameters; +- (id)initWithURL:(NSURL *)aURL parameters:(NSArray *)theParameters files:(NSDictionary*)theFiles; + +- (id)initWithURL:(NSURL *)aURL + method:(NSString *)aMethod + parameters:(NSArray *)theParameters + files:(NSDictionary*)theFiles; + +- (void)perform:(OAConsumer *)consumer + token:(OAToken *)token + realm:(NSString *)realm + delegate:(NSObject *)aDelegate + didFinish:(SEL)finished; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OACall.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OACall.m new file mode 100644 index 0000000..dcc88b9 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OACall.m @@ -0,0 +1,168 @@ +// +// OACall.m +// OAuthConsumer +// +// Created by Alberto García Hierro on 04/09/08. +// Copyright 2008 Alberto García Hierro. All rights reserved. +// bynotes.com + +#import "OAConsumer.h" +#import "OAToken.h" +#import "OAProblem.h" +#import "OADataFetcher.h" +#import "OAServiceTicket.h" +#import "OAMutableURLRequest.h" +#import "OACall.h" + +@interface OACall (Private) + +- (void)callFinished:(OAServiceTicket *)ticket withData:(NSData *)data; +- (void)callFailed:(OAServiceTicket *)ticket withError:(NSError *)error; + +@end + +@implementation OACall + +@synthesize url, method, parameters, files, ticket; + +- (id)init { + return [self initWithURL:nil + method:nil + parameters:nil + files:nil]; +} + +- (id)initWithURL:(NSURL *)aURL { + return [self initWithURL:aURL + method:nil + parameters:nil + files:nil]; +} + +- (id)initWithURL:(NSURL *)aURL method:(NSString *)aMethod { + return [self initWithURL:aURL + method:aMethod + parameters:nil + files:nil]; +} + +- (id)initWithURL:(NSURL *)aURL parameters:(NSArray *)theParameters { + return [self initWithURL:aURL + method:nil + parameters:theParameters]; +} + +- (id)initWithURL:(NSURL *)aURL method:(NSString *)aMethod parameters:(NSArray *)theParameters { + return [self initWithURL:aURL + method:aMethod + parameters:theParameters + files:nil]; +} + +- (id)initWithURL:(NSURL *)aURL parameters:(NSArray *)theParameters files:(NSDictionary*)theFiles { + return [self initWithURL:aURL + method:@"POST" + parameters:theParameters + files:theFiles]; +} + +- (id)initWithURL:(NSURL *)aURL + method:(NSString *)aMethod + parameters:(NSArray *)theParameters + files:(NSDictionary*)theFiles { + url = [aURL retain]; + method = [aMethod retain]; + parameters = [theParameters retain]; + files = [theFiles retain]; + fetcher = nil; + request = nil; + + return self; +} + +- (void)dealloc { + [url release]; + [method release]; + [parameters release]; + [files release]; + [fetcher release]; + [request release]; + [ticket release]; + [super dealloc]; +} + +- (void)callFailed:(OAServiceTicket *)aTicket withError:(NSError *)error { + NSLog(@"error body: %@", aTicket.body); + self.ticket = aTicket; + [aTicket release]; + OAProblem *problem = [OAProblem problemWithResponseBody:ticket.body]; + if (problem) { + [delegate call:self failedWithProblem:problem]; + } else { + [delegate call:self failedWithError:error]; + } +} + +- (void)callFinished:(OAServiceTicket *)aTicket withData:(NSData *)data { + self.ticket = aTicket; + [aTicket release]; + if (ticket.didSucceed) { +// NSLog(@"Call body: %@", ticket.body); + [delegate performSelector:finishedSelector withObject:self withObject:ticket.body]; + } else { +// NSLog(@"Failed call body: %@", ticket.body); + [self callFailed:[ticket retain] withError:nil]; + } +} + +- (void)perform:(OAConsumer *)consumer + token:(OAToken *)token + realm:(NSString *)realm + delegate:(NSObject *)aDelegate + didFinish:(SEL)finished + +{ + delegate = aDelegate; + finishedSelector = finished; + + request = [[OAMutableURLRequest alloc] initWithURL:url + consumer:consumer + token:token + realm:realm + signatureProvider:nil]; + if(method) { + [request setHTTPMethod:method]; + } + + if (self.parameters) { + [request setParameters:self.parameters]; + } + if (self.files) { + for (NSString *key in self.files) { + [request attachFileWithName:@"file" filename:NSLocalizedString(@"Photo.jpg", @"") data:[self.files objectForKey:key]]; + } + } + fetcher = [[OADataFetcher alloc] init]; + [fetcher fetchDataWithRequest:request + delegate:self + didFinishSelector:@selector(callFinished:withData:) + didFailSelector:@selector(callFailed:withError:)]; +} + +/*- (BOOL)isEqual:(id)object { + if ([object isKindOfClass:[self class]]) { + return [self isEqualToCall:(OACall *)object]; + } + return NO; +} + +- (BOOL)isEqualToCall:(OACall *)aCall { + return (delegate == aCall->delegate + && finishedSelector == aCall->finishedSelector + && [url isEqualTo:aCall.url] + && [method isEqualToString:aCall.method] + && [parameters isEqualToArray:aCall.parameters] + && [files isEqualToDictionary:aCall.files]); +}*/ + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAConsumer.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAConsumer.h new file mode 100644 index 0000000..5990028 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAConsumer.h @@ -0,0 +1,42 @@ +// +// OAConsumer.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import + + +@interface OAConsumer : NSObject { +@protected + NSString *key; + NSString *secret; +} +@property(copy, readwrite) NSString *key; +@property(copy, readwrite) NSString *secret; + +- (id)initWithKey:(const NSString *)aKey secret:(const NSString *)aSecret; + +- (BOOL)isEqualToConsumer:(OAConsumer *)aConsumer; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAConsumer.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAConsumer.m new file mode 100644 index 0000000..1545c95 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAConsumer.m @@ -0,0 +1,53 @@ +// +// OAConsumer.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "OAConsumer.h" + + +@implementation OAConsumer +@synthesize key, secret; + +#pragma mark init + +- (id)initWithKey:(const NSString *)aKey secret:(const NSString *)aSecret { + [super init]; + self.key = [aKey retain]; + self.secret = [aSecret retain]; + return self; +} + +- (BOOL)isEqual:(id)object { + if ([object isKindOfClass:[self class]]) { + return [self isEqualToConsumer:(OAConsumer*)object]; + } + return NO; +} + +- (BOOL)isEqualToConsumer:(OAConsumer *)aConsumer { + return ([self.key isEqualToString:aConsumer.key] && + [self.secret isEqualToString:aConsumer.secret]); +} + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OADataFetcher.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OADataFetcher.h new file mode 100644 index 0000000..8afeb33 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OADataFetcher.h @@ -0,0 +1,44 @@ +// +// OADataFetcher.h +// OAuthConsumer +// +// Created by Jon Crosby on 11/5/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "OAMutableURLRequest.h" +#import "OAServiceTicket.h" + + +@interface OADataFetcher : NSObject { +@private + OAMutableURLRequest *request; + NSURLResponse *response; + NSURLConnection *connection; + NSMutableData *responseData; + id delegate; + SEL didFinishSelector; + SEL didFailSelector; +} + +- (void)fetchDataWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OADataFetcher.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OADataFetcher.m new file mode 100644 index 0000000..08cf295 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OADataFetcher.m @@ -0,0 +1,89 @@ +// +// OADataFetcher.m +// OAuthConsumer +// +// Created by Jon Crosby on 11/5/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OADataFetcher.h" + + +@implementation OADataFetcher + +- (id)init { + [super init]; + responseData = [[NSMutableData alloc] init]; + return self; +} + +- (void)dealloc { + [connection release]; + [response release]; + [responseData release]; + [request release]; + [super dealloc]; +} + +/* Protocol for async URL loading */ +- (void)connection:(NSURLConnection *)aConnection didReceiveResponse:(NSURLResponse *)aResponse { + [response release]; + response = [aResponse retain]; + [responseData setLength:0]; +} + +- (void)connection:(NSURLConnection *)aConnection didFailWithError:(NSError *)error { + OAServiceTicket *ticket = [[OAServiceTicket alloc] initWithRequest:request + response:response + data:responseData + didSucceed:NO]; + + [delegate performSelector:didFailSelector withObject:ticket withObject:error]; + [ticket release]; +} + +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { + [responseData appendData:data]; +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)connection { + OAServiceTicket *ticket = [[OAServiceTicket alloc] initWithRequest:request + response:response + data:responseData + didSucceed:[(NSHTTPURLResponse *)response statusCode] < 400]; + + [delegate performSelector:didFinishSelector withObject:ticket withObject:responseData]; + [ticket release]; +} + +- (void)fetchDataWithRequest:(OAMutableURLRequest *)aRequest delegate:(id)aDelegate didFinishSelector:(SEL)finishSelector didFailSelector:(SEL)failSelector { + [request release]; + request = [aRequest retain]; + delegate = aDelegate; + didFinishSelector = finishSelector; + didFailSelector = failSelector; + + [request prepare]; + + connection = [[NSURLConnection alloc] initWithRequest:aRequest delegate:self]; +} + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAHMAC_SHA1SignatureProvider.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAHMAC_SHA1SignatureProvider.h new file mode 100644 index 0000000..d259c4e --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAHMAC_SHA1SignatureProvider.h @@ -0,0 +1,32 @@ +// +// OAHMAC_SHA1SignatureProvider.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "OASignatureProviding.h" + + +@interface OAHMAC_SHA1SignatureProvider : NSObject +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAHMAC_SHA1SignatureProvider.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAHMAC_SHA1SignatureProvider.m new file mode 100644 index 0000000..63bb7ea --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAHMAC_SHA1SignatureProvider.m @@ -0,0 +1,58 @@ +// +// OAHMAC_SHA1SignatureProvider.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OAHMAC_SHA1SignatureProvider.h" + +#include "hmac.h" +#include "Base64Transcoder.h" + +@implementation OAHMAC_SHA1SignatureProvider + +- (NSString *)name { + return @"HMAC-SHA1"; +} + +- (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret { + NSData *secretData = [[secret dataUsingEncoding:NSUTF8StringEncoding] retain]; + NSData *clearTextData = [[text dataUsingEncoding:NSUTF8StringEncoding] retain]; + unsigned char result[20]; + hmac_sha1((unsigned char *)[clearTextData bytes], [clearTextData length], (unsigned char *)[secretData bytes], [secretData length], result); + [secretData release]; + [clearTextData release]; + + //Base64 Encoding + + char base64Result[32]; + size_t theResultLength = 32; + Base64EncodeData(result, 20, base64Result, &theResultLength); + NSData *theData = [NSData dataWithBytes:base64Result length:theResultLength]; + + NSString *base64EncodedResult = [[[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding] autorelease]; + + return base64EncodedResult; +} + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAMutableURLRequest.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAMutableURLRequest.h new file mode 100644 index 0000000..c080bd1 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAMutableURLRequest.h @@ -0,0 +1,67 @@ +// +// OAMutableURLRequest.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "OAConsumer.h" +#import "OAToken.h" +#import "OAHMAC_SHA1SignatureProvider.h" +#import "OASignatureProviding.h" +#import "NSMutableURLRequest+Parameters.h" +#import "NSURL+Base.h" + + +@interface OAMutableURLRequest : NSMutableURLRequest { +@protected + OAConsumer *consumer; + OAToken *token; + NSString *realm; + NSString *signature; + id signatureProvider; + NSString *nonce; + NSString *timestamp; +} +@property(readonly) NSString *signature; +@property(readonly) NSString *nonce; + +- (id)initWithURL:(NSURL *)aUrl + consumer:(OAConsumer *)aConsumer + token:(OAToken *)aToken + realm:(NSString *)aRealm +signatureProvider:(id)aProvider; + +- (id)initWithURL:(NSURL *)aUrl + consumer:(OAConsumer *)aConsumer + token:(OAToken *)aToken + realm:(NSString *)aRealm +signatureProvider:(id)aProvider + nonce:(NSString *)aNonce + timestamp:(NSString *)aTimestamp; + +- (void)prepare; + +- (NSString *)signatureBaseString; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAMutableURLRequest.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAMutableURLRequest.m new file mode 100644 index 0000000..24ae11e --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAMutableURLRequest.m @@ -0,0 +1,199 @@ +// +// OAMutableURLRequest.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OAMutableURLRequest.h" + + +@interface OAMutableURLRequest (Private) +- (void)_generateTimestamp; +- (void)_generateNonce; +@end + +@implementation OAMutableURLRequest +@synthesize signature, nonce; + +#pragma mark init + +- (id)initWithURL:(NSURL *)aUrl + consumer:(OAConsumer *)aConsumer + token:(OAToken *)aToken + realm:(NSString *)aRealm +signatureProvider:(id)aProvider { + [super initWithURL:aUrl + cachePolicy:NSURLRequestReloadIgnoringCacheData + timeoutInterval:10.0]; + + consumer = aConsumer; + + // empty token for Unauthorized Request Token transaction + if (aToken == nil) { + token = [[OAToken alloc] init]; + } else { + token = [aToken retain]; + } + + if (aRealm == nil) { + realm = @""; + } else { + realm = [aRealm copy]; + } + + // default to HMAC-SHA1 + if (aProvider == nil) { + signatureProvider = [[OAHMAC_SHA1SignatureProvider alloc] init]; + } else { + signatureProvider = [aProvider retain]; + } + + [self _generateTimestamp]; + [self _generateNonce]; + + return self; +} + +// Setting a timestamp and nonce to known +// values can be helpful for testing +- (id)initWithURL:(NSURL *)aUrl + consumer:(OAConsumer *)aConsumer + token:(OAToken *)aToken + realm:(NSString *)aRealm +signatureProvider:(id)aProvider + nonce:(NSString *)aNonce + timestamp:(NSString *)aTimestamp { + [self initWithURL:aUrl + consumer:aConsumer + token:aToken + realm:aRealm + signatureProvider:aProvider]; + + nonce = [aNonce copy]; + timestamp = [aTimestamp copy]; + + return self; +} + +- (void)prepare { + // sign +// NSLog(@"Base string is: %@", [self _signatureBaseString]); + signature = [signatureProvider signClearText:[self signatureBaseString] + withSecret:[NSString stringWithFormat:@"%@&%@", + [consumer.secret encodedURLParameterString], + token.secret ? [token.secret encodedURLParameterString] : @""]]; + + // set OAuth headers + NSMutableArray *chunks = [[NSMutableArray alloc] init]; + [chunks addObject:[NSString stringWithFormat:@"realm=\"%@\"", [realm encodedURLParameterString]]]; + [chunks addObject:[NSString stringWithFormat:@"oauth_consumer_key=\"%@\"", [consumer.key encodedURLParameterString]]]; + + NSDictionary *tokenParameters = [token parameters]; + for (NSString *k in tokenParameters) { + [chunks addObject:[NSString stringWithFormat:@"%@=\"%@\"", k, [[tokenParameters objectForKey:k] encodedURLParameterString]]]; + } + + [chunks addObject:[NSString stringWithFormat:@"oauth_signature_method=\"%@\"", [[signatureProvider name] encodedURLParameterString]]]; + [chunks addObject:[NSString stringWithFormat:@"oauth_signature=\"%@\"", [signature encodedURLParameterString]]]; + [chunks addObject:[NSString stringWithFormat:@"oauth_timestamp=\"%@\"", timestamp]]; + [chunks addObject:[NSString stringWithFormat:@"oauth_nonce=\"%@\"", nonce]]; + [chunks addObject:@"oauth_version=\"1.0\""]; + + NSString *oauthHeader = [NSString stringWithFormat:@"OAuth %@", [chunks componentsJoinedByString:@", "]]; + [chunks release]; + + [self setValue:oauthHeader forHTTPHeaderField:@"Authorization"]; +} + +- (void)_generateTimestamp { + [timestamp release]; + timestamp = [[NSString alloc]initWithFormat:@"%d", time(NULL)]; +} + +- (void)_generateNonce { + CFUUIDRef theUUID = CFUUIDCreate(NULL); + CFStringRef string = CFUUIDCreateString(NULL, theUUID); + NSMakeCollectable(theUUID); + if (nonce) { + CFRelease(nonce); + } + nonce = (NSString *)string; +} + +- (NSString *)signatureBaseString { + // OAuth Spec, Section 9.1.1 "Normalize Request Parameters" + // build a sorted array of both request parameters and OAuth header parameters + NSDictionary *tokenParameters = [token parameters]; + // 6 being the number of OAuth params in the Signature Base String + NSArray *parameters = [self parameters]; + NSMutableArray *parameterPairs = [[NSMutableArray alloc] initWithCapacity:(5 + [parameters count] + [tokenParameters count])]; + + OARequestParameter *parameter; + parameter = [[OARequestParameter alloc] initWithName:@"oauth_consumer_key" value:consumer.key]; + + [parameterPairs addObject:[parameter URLEncodedNameValuePair]]; + [parameter release]; + parameter = [[OARequestParameter alloc] initWithName:@"oauth_signature_method" value:[signatureProvider name]]; + [parameterPairs addObject:[parameter URLEncodedNameValuePair]]; + [parameter release]; + parameter = [[OARequestParameter alloc] initWithName:@"oauth_timestamp" value:timestamp]; + [parameterPairs addObject:[parameter URLEncodedNameValuePair]]; + [parameter release]; + parameter = [[OARequestParameter alloc] initWithName:@"oauth_nonce" value:nonce]; + [parameterPairs addObject:[parameter URLEncodedNameValuePair]]; + [parameter release]; + parameter = [[OARequestParameter alloc] initWithName:@"oauth_version" value:@"1.0"] ; + [parameterPairs addObject:[parameter URLEncodedNameValuePair]]; + [parameter release]; + + for(NSString *k in tokenParameters) { + [parameterPairs addObject:[[OARequestParameter requestParameter:k value:[tokenParameters objectForKey:k]] URLEncodedNameValuePair]]; + } + + if (![[self valueForHTTPHeaderField:@"Content-Type"] hasPrefix:@"multipart/form-data"]) { + for (OARequestParameter *param in parameters) { + [parameterPairs addObject:[param URLEncodedNameValuePair]]; + } + } + + NSArray *sortedPairs = [parameterPairs sortedArrayUsingSelector:@selector(compare:)]; + NSString *normalizedRequestParameters = [sortedPairs componentsJoinedByString:@"&"]; + [parameterPairs release]; + // NSLog(@"Normalized: %@", normalizedRequestParameters); + // OAuth Spec, Section 9.1.2 "Concatenate Request Elements" + return [NSString stringWithFormat:@"%@&%@&%@", + [self HTTPMethod], + [[[self URL] URLStringWithoutQuery] encodedURLParameterString], + [normalizedRequestParameters encodedURLString]]; +} + +- (void) dealloc +{ + [token release]; + [(NSObject*)signatureProvider release]; + [timestamp release]; + CFRelease(nonce); + [super dealloc]; +} + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAPlaintextSignatureProvider.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAPlaintextSignatureProvider.h new file mode 100644 index 0000000..96bb2f2 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAPlaintextSignatureProvider.h @@ -0,0 +1,31 @@ +// +// OAPlaintextSignatureProvider.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "OASignatureProviding.h" + +@interface OAPlaintextSignatureProvider : NSObject +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAPlaintextSignatureProvider.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAPlaintextSignatureProvider.m new file mode 100644 index 0000000..9cc4d63 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAPlaintextSignatureProvider.m @@ -0,0 +1,40 @@ +// +// OAPlaintextSignatureProvider.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OAPlaintextSignatureProvider.h" + + +@implementation OAPlaintextSignatureProvider + +- (NSString *)name { + return @"PLAINTEXT"; +} + +- (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret { + return secret; +} + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAProblem.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAProblem.h new file mode 100644 index 0000000..fe64c70 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAProblem.h @@ -0,0 +1,53 @@ +// +// OAProblem.h +// OAuthConsumer +// +// Created by Alberto García Hierro on 03/09/08. +// Copyright 2008 Alberto García Hierro. All rights reserved. +// bynotes.com + +#import + +enum { + kOAProblemSignatureMethodRejected = 0, + kOAProblemParameterAbsent, + kOAProblemVersionRejected, + kOAProblemConsumerKeyUnknown, + kOAProblemTokenRejected, + kOAProblemSignatureInvalid, + kOAProblemNonceUsed, + kOAProblemTimestampRefused, + kOAProblemTokenExpired, + kOAProblemTokenNotRenewable +}; + +@interface OAProblem : NSObject { + const NSString *problem; +} + +@property (readonly) const NSString *problem; + +- (id)initWithProblem:(const NSString *)aProblem; +- (id)initWithResponseBody:(const NSString *)response; + +- (BOOL)isEqualToProblem:(OAProblem *)aProblem; +- (BOOL)isEqualToString:(const NSString *)aProblem; +- (BOOL)isEqualTo:(id)aProblem; +- (int)code; + ++ (OAProblem *)problemWithResponseBody:(const NSString *)response; + ++ (const NSArray *)validProblems; + ++ (OAProblem *)SignatureMethodRejected; ++ (OAProblem *)ParameterAbsent; ++ (OAProblem *)VersionRejected; ++ (OAProblem *)ConsumerKeyUnknown; ++ (OAProblem *)TokenRejected; ++ (OAProblem *)SignatureInvalid; ++ (OAProblem *)NonceUsed; ++ (OAProblem *)TimestampRefused; ++ (OAProblem *)TokenExpired; ++ (OAProblem *)TokenNotRenewable; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAProblem.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAProblem.m new file mode 100644 index 0000000..7a885a3 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAProblem.m @@ -0,0 +1,165 @@ +// +// OAProblem.m +// OAuthConsumer +// +// Created by Alberto García Hierro on 03/09/08. +// Copyright 2008 Alberto García Hierro. All rights reserved. +// bynotes.com + +#import "OAProblem.h" + +const NSString *signature_method_rejected = @"signature_method_rejected"; +const NSString *parameter_absent = @"parameter_absent"; +const NSString *version_rejected = @"version_rejected"; +const NSString *consumer_key_unknown = @"consumer_key_unknown"; +const NSString *token_rejected = @"token_rejected"; +const NSString *signature_invalid = @"signature_invalid"; +const NSString *nonce_used = @"nonce_used"; +const NSString *timestamp_refused = @"timestamp_refused"; +const NSString *token_expired = @"token_expired"; +const NSString *token_not_renewable = @"token_not_renewable"; + +@implementation OAProblem + +@synthesize problem; + +- (id)initWithPointer:(const NSString *) aPointer +{ + [super init]; + problem = aPointer; + return self; +} + +- (id)initWithProblem:(const NSString *) aProblem +{ + NSUInteger idx = [[OAProblem validProblems] indexOfObject:aProblem]; + if (idx == NSNotFound) { + return nil; + } + + return [self initWithPointer: [[OAProblem validProblems] objectAtIndex:idx]]; +} + +- (id)initWithResponseBody:(const NSString *) response +{ + NSArray *fields = [response componentsSeparatedByString:@"&"]; + for (NSString *field in fields) { + if ([field hasPrefix:@"oauth_problem="]) { + NSString *value = [[field componentsSeparatedByString:@"="] objectAtIndex:1]; + return [self initWithProblem:value]; + } + } + + return nil; +} + ++ (OAProblem *)problemWithResponseBody:(const NSString *) response +{ + return [[[OAProblem alloc] initWithResponseBody:response] autorelease]; +} + ++ (const NSArray *)validProblems +{ + static NSArray *array; + if (!array) { + array = [[NSArray alloc] initWithObjects:signature_method_rejected, + parameter_absent, + version_rejected, + consumer_key_unknown, + token_rejected, + signature_invalid, + nonce_used, + timestamp_refused, + token_expired, + token_not_renewable, + nil]; + } + + return array; +} + +- (BOOL)isEqualToProblem:(OAProblem *) aProblem +{ + return [problem isEqualToString:(NSString *)aProblem->problem]; +} + +- (BOOL)isEqualToString:(const NSString *) aProblem +{ + return [problem isEqualToString:(NSString *)aProblem]; +} + +- (BOOL)isEqualTo:(id) aProblem +{ + if ([aProblem isKindOfClass:[NSString class]]) { + return [self isEqualToString:aProblem]; + } + + if ([aProblem isKindOfClass:[OAProblem class]]) { + return [self isEqualToProblem:aProblem]; + } + + return NO; +} + +- (int)code { + return [[[self class] validProblems] indexOfObject:problem]; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"OAuth Problem: %@", (NSString *)problem]; +} + +#pragma mark class_methods + ++ (OAProblem *)SignatureMethodRejected +{ + return [[[OAProblem alloc] initWithPointer:signature_method_rejected] autorelease]; +} + ++ (OAProblem *)ParameterAbsent +{ + return [[[OAProblem alloc] initWithPointer:parameter_absent] autorelease]; +} + ++ (OAProblem *)VersionRejected +{ + return [[[OAProblem alloc] initWithPointer:version_rejected] autorelease]; +} + ++ (OAProblem *)ConsumerKeyUnknown +{ + return [[[OAProblem alloc] initWithPointer:consumer_key_unknown] autorelease]; +} + ++ (OAProblem *)TokenRejected +{ + return [[[OAProblem alloc] initWithPointer:token_rejected] autorelease]; +} + ++ (OAProblem *)SignatureInvalid +{ + return [[[OAProblem alloc] initWithPointer:signature_invalid] autorelease]; +} + ++ (OAProblem *)NonceUsed +{ + return [[[OAProblem alloc] initWithPointer:nonce_used] autorelease]; +} + ++ (OAProblem *)TimestampRefused +{ + return [[[OAProblem alloc] initWithPointer:timestamp_refused] autorelease]; +} + ++ (OAProblem *)TokenExpired +{ + return [[[OAProblem alloc] initWithPointer:token_expired] autorelease]; +} + ++ (OAProblem *)TokenNotRenewable +{ + return [[[OAProblem alloc] initWithPointer:token_not_renewable] autorelease]; +} + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OARequestParameter.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OARequestParameter.h new file mode 100644 index 0000000..de73ea8 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OARequestParameter.h @@ -0,0 +1,48 @@ +// +// OARequestParameter.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "NSString+URLEncoding.h" + + +@interface OARequestParameter : NSObject { +@protected + NSString *name; + NSString *value; +} +@property(copy, readwrite) NSString *name; +@property(copy, readwrite) NSString *value; + +- (id)initWithName:(NSString *)aName value:(NSString *)aValue; +- (NSString *)URLEncodedName; +- (NSString *)URLEncodedValue; +- (NSString *)URLEncodedNameValuePair; + +- (BOOL)isEqualToRequestParameter:(OARequestParameter *)parameter; + ++ (id)requestParameter:(NSString *)aName value:(NSString *)aValue; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OARequestParameter.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OARequestParameter.m new file mode 100644 index 0000000..236b03a --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OARequestParameter.m @@ -0,0 +1,72 @@ +// +// OARequestParameter.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OARequestParameter.h" + + +@implementation OARequestParameter +@synthesize name, value; + +- (id)initWithName:(NSString *)aName value:(NSString *)aValue { + [super init]; + self.name = aName; + self.value = aValue; + return self; +} + +- (NSString *)URLEncodedName { + return self.name; +// return [self.name encodedURLParameterString]; +} + +- (NSString *)URLEncodedValue { + return [self.value encodedURLParameterString]; +} + +- (NSString *)URLEncodedNameValuePair { + return [NSString stringWithFormat:@"%@=%@", [self URLEncodedName], [self URLEncodedValue]]; +} + +- (BOOL)isEqual:(id)object { + if ([object isKindOfClass:[self class]]) { + return [self isEqualToRequestParameter:(OARequestParameter *)object]; + } + + return NO; +} + +- (BOOL)isEqualToRequestParameter:(OARequestParameter *)parameter { + return ([self.name isEqualToString:parameter.name] && + [self.value isEqualToString:parameter.value]); +} + + ++ (id)requestParameter:(NSString *)aName value:(NSString *)aValue +{ + return [[[self alloc] initWithName:aName value:aValue] autorelease]; +} + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAServiceTicket.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAServiceTicket.h new file mode 100644 index 0000000..63852b9 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAServiceTicket.h @@ -0,0 +1,46 @@ +// +// OAServiceTicket.h +// OAuthConsumer +// +// Created by Jon Crosby on 11/5/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import "OAMutableURLRequest.h" + + +@interface OAServiceTicket : NSObject { +@private + OAMutableURLRequest *request; + NSURLResponse *response; + NSData *data; + BOOL didSucceed; +} +@property(readonly) OAMutableURLRequest *request; +@property(readonly) NSURLResponse *response; +@property(readonly) NSData *data; +@property(readonly) BOOL didSucceed; +@property(readonly) NSString *body; + +- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSURLResponse *)aResponse data:(NSData *)aData didSucceed:(BOOL)success; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAServiceTicket.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAServiceTicket.m new file mode 100644 index 0000000..0dbe90c --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAServiceTicket.m @@ -0,0 +1,51 @@ +// +// OAServiceTicket.m +// OAuthConsumer +// +// Created by Jon Crosby on 11/5/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "OAServiceTicket.h" + + +@implementation OAServiceTicket +@synthesize request, response, data, didSucceed; + +- (id)initWithRequest:(OAMutableURLRequest *)aRequest response:(NSURLResponse *)aResponse data:(NSData *)aData didSucceed:(BOOL)success { + [super init]; + request = aRequest; + response = aResponse; + data = aData; + didSucceed = success; + return self; +} + +- (NSString *)body +{ + if (!data) { + return nil; + } + + return [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; +} + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OASignatureProviding.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OASignatureProviding.h new file mode 100644 index 0000000..6fc5f98 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OASignatureProviding.h @@ -0,0 +1,34 @@ +// +// OASignatureProviding.h +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import + + +@protocol OASignatureProviding + +- (NSString *)name; +- (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAToken.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAToken.h new file mode 100644 index 0000000..eb2c2bf --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAToken.h @@ -0,0 +1,72 @@ +// +// OAToken.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +@interface OAToken : NSObject { +@protected + NSString *key; + NSString *secret; + NSString *session; + NSNumber *duration; + NSMutableDictionary *attributes; + NSDate *created; + BOOL renewable; + BOOL forRenewal; +} +@property(retain, readwrite) NSString *key; +@property(retain, readwrite) NSString *secret; +@property(retain, readwrite) NSString *session; +@property(retain, readwrite) NSNumber *duration; +@property(retain, readwrite) NSMutableDictionary *attributes; +@property(readwrite, getter=isForRenewal) BOOL forRenewal; + +- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret; +- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret session:(NSString *)aSession + duration:(NSNumber *)aDuration attributes:(NSDictionary *)theAttributes created:(NSDate *)creation + renewable:(BOOL)renew; +- (id)initWithHTTPResponseBody:(NSString *)body; + +- (id)initWithUserDefaultsUsingServiceProviderName:(NSString *)provider prefix:(NSString *)prefix; +- (int)storeInUserDefaultsWithServiceProviderName:(NSString *)provider prefix:(NSString *)prefix; + +- (BOOL)isValid; + +- (void)setAttribute:(NSString *)aKey value:(NSString *)aValue; +- (NSString *)attribute:(NSString *)aKey; +- (void)setAttributesWithString:(NSString *)aAttributes; +- (NSString *)attributeString; + +- (BOOL)hasExpired; +- (BOOL)isRenewable; +- (void)setDurationWithString:(NSString *)aDuration; +- (BOOL)hasAttributes; +- (NSDictionary *)parameters; + +- (BOOL)isEqualToToken:(OAToken *)aToken; + ++ (void)removeFromUserDefaultsWithServiceProviderName:(const NSString *)provider prefix:(const NSString *)prefix; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAToken.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAToken.m new file mode 100644 index 0000000..a2ab54a --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAToken.m @@ -0,0 +1,328 @@ +// +// OAToken.m +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "NSString+URLEncoding.h" +#import "OAToken.h" + +@interface OAToken (Private) + ++ (NSString *)settingsKey:(const NSString *)name provider:(const NSString *)provider prefix:(const NSString *)prefix; ++ (id)loadSetting:(const NSString *)name provider:(const NSString *)provider prefix:(const NSString *)prefix; ++ (void)saveSetting:(NSString *)name object:(id)object provider:(const NSString *)provider prefix:(const NSString *)prefix; ++ (NSNumber *)durationWithString:(NSString *)aDuration; ++ (NSDictionary *)attributesWithString:(NSString *)theAttributes; + +@end + +@implementation OAToken + +@synthesize key, secret, session, duration, attributes, forRenewal; + +#pragma mark init + +- (id)init { + return [self initWithKey:nil secret:nil]; +} + +- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret { + return [self initWithKey:aKey secret:aSecret session:nil duration:nil + attributes:nil created:nil renewable:NO]; +} + +- (id)initWithKey:(NSString *)aKey secret:(NSString *)aSecret session:(NSString *)aSession + duration:(NSNumber *)aDuration attributes:(NSDictionary *)theAttributes created:(NSDate *)creation + renewable:(BOOL)renew { + [super init]; + self.key = aKey; + self.secret = aSecret; + self.session = aSession; + self.duration = aDuration; + self.attributes = theAttributes; + created = [creation retain]; + renewable = renew; + forRenewal = NO; + + return self; +} + +- (id)initWithHTTPResponseBody:(const NSString *)body { + NSString *aKey = nil; + NSString *aSecret = nil; + NSString *aSession = nil; + NSNumber *aDuration = nil; + NSDate *creationDate = nil; + NSDictionary *attrs = nil; + BOOL renew = NO; + NSArray *pairs = [body componentsSeparatedByString:@"&"]; + + for (NSString *pair in pairs) { + NSArray *elements = [pair componentsSeparatedByString:@"="]; + if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token"]) { + aKey = [elements objectAtIndex:1]; + } else if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token_secret"]) { + aSecret = [elements objectAtIndex:1]; + } else if ([[elements objectAtIndex:0] isEqualToString:@"oauth_session_handle"]) { + aSession = [elements objectAtIndex:1]; + } else if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token_duration"]) { + aDuration = [[self class] durationWithString:[elements objectAtIndex:1]]; + creationDate = [NSDate date]; + } else if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token_attributes"]) { + attrs = [[self class] attributesWithString:[[elements objectAtIndex:1] decodedURLString]]; + } else if ([[elements objectAtIndex:0] isEqualToString:@"oauth_token_renewable"]) { + NSString *lowerCase = [[elements objectAtIndex:1] lowercaseString]; + if ([lowerCase isEqualToString:@"true"] || [lowerCase isEqualToString:@"t"]) { + renew = YES; + } + } + } + + return [self initWithKey:aKey secret:aSecret session:aSession duration:aDuration + attributes:attrs created:creationDate renewable:renew]; +} + +- (id)initWithUserDefaultsUsingServiceProviderName:(const NSString *)provider prefix:(const NSString *)prefix { + [super init]; + self.key = [OAToken loadSetting:@"key" provider:provider prefix:prefix]; + self.secret = [OAToken loadSetting:@"secret" provider:provider prefix:prefix]; + self.session = [OAToken loadSetting:@"session" provider:provider prefix:prefix]; + self.duration = [OAToken loadSetting:@"duration" provider:provider prefix:prefix]; + self.attributes = [OAToken loadSetting:@"attributes" provider:provider prefix:prefix]; + created = [OAToken loadSetting:@"created" provider:provider prefix:prefix]; + renewable = [[OAToken loadSetting:@"renewable" provider:provider prefix:prefix] boolValue]; + + if (![self isValid]) { + [self autorelease]; + return nil; + } + + return self; +} + +#pragma mark dealloc + +- (void)dealloc { + self.key = nil; + self.secret = nil; + self.duration = nil; + self.attributes = nil; + [super dealloc]; +} + +#pragma mark settings + +- (BOOL)isValid { + return (key != nil && ![key isEqualToString:@""] && secret != nil && ![secret isEqualToString:@""]); +} + +- (int)storeInUserDefaultsWithServiceProviderName:(const NSString *)provider prefix:(const NSString *)prefix { + [OAToken saveSetting:@"key" object:key provider:provider prefix:prefix]; + [OAToken saveSetting:@"secret" object:secret provider:provider prefix:prefix]; + [OAToken saveSetting:@"created" object:created provider:provider prefix:prefix]; + [OAToken saveSetting:@"duration" object:duration provider:provider prefix:prefix]; + [OAToken saveSetting:@"session" object:session provider:provider prefix:prefix]; + [OAToken saveSetting:@"attributes" object:attributes provider:provider prefix:prefix]; + [OAToken saveSetting:@"renewable" object:renewable ? @"t" : @"f" provider:provider prefix:prefix]; + + [[NSUserDefaults standardUserDefaults] synchronize]; + return(0); +} + +#pragma mark duration + +- (void)setDurationWithString:(NSString *)aDuration { + self.duration = [[self class] durationWithString:aDuration]; +} + +- (BOOL)hasExpired +{ + return created && [created timeIntervalSinceNow] > [duration intValue]; +} + +- (BOOL)isRenewable +{ + return session && renewable && created && [created timeIntervalSinceNow] < (2 * [duration intValue]); +} + + +#pragma mark attributes + +- (void)setAttribute:(const NSString *)aKey value:(const NSString *)aAttribute { + if (!attributes) { + attributes = [[NSMutableDictionary alloc] init]; + } + [attributes setObject: aAttribute forKey: aKey]; +} + +- (void)setAttributes:(NSDictionary *)theAttributes { + [attributes release]; + if (theAttributes) { + attributes = [[NSMutableDictionary alloc] initWithDictionary:theAttributes]; + }else { + attributes = nil; + } + +} + +- (BOOL)hasAttributes { + return (attributes && [attributes count] > 0); +} + +- (NSString *)attributeString { + if (![self hasAttributes]) { + return @""; + } + + NSMutableArray *chunks = [[NSMutableArray alloc] init]; + for(NSString *aKey in self->attributes) { + [chunks addObject:[NSString stringWithFormat:@"%@:%@", aKey, [attributes objectForKey:aKey]]]; + } + NSString *attrs = [chunks componentsJoinedByString:@";"]; + [chunks release]; + return attrs; +} + +- (NSString *)attribute:(NSString *)aKey +{ + return [attributes objectForKey:aKey]; +} + +- (void)setAttributesWithString:(NSString *)theAttributes +{ + self.attributes = [[self class] attributesWithString:theAttributes]; +} + +- (NSDictionary *)parameters +{ + NSMutableDictionary *params = [[[NSMutableDictionary alloc] init] autorelease]; + + if (key) { + [params setObject:key forKey:@"oauth_token"]; + if ([self isForRenewal]) { + [params setObject:session forKey:@"oauth_session_handle"]; + } + } else { + if (duration) { + [params setObject:[duration stringValue] forKey: @"oauth_token_duration"]; + } + if ([attributes count]) { + [params setObject:[self attributeString] forKey:@"oauth_token_attributes"]; + } + } + return params; +} + +#pragma mark comparisions + +- (BOOL)isEqual:(id)object { + if([object isKindOfClass:[self class]]) { + return [self isEqualToToken:(OAToken *)object]; + } + return NO; +} + +- (BOOL)isEqualToToken:(OAToken *)aToken { + /* Since ScalableOAuth determines that the token may be + renewed using the same key and secret, we must also + check the creation date */ + if ([self.key isEqualToString:aToken.key] && + [self.secret isEqualToString:aToken.secret]) { + /* May be nil */ + if (created == aToken->created || [created isEqualToDate:aToken->created]) { + return YES; + } + } + + return NO; +} + +#pragma mark class_functions + ++ (NSString *)settingsKey:(NSString *)name provider:(NSString *)provider prefix:(NSString *)prefix { + return [NSString stringWithFormat:@"OAUTH_%@_%@_%@", provider, prefix, [name uppercaseString]]; +} + ++ (id)loadSetting:(NSString *)name provider:(NSString *)provider prefix:(NSString *)prefix { + return [[NSUserDefaults standardUserDefaults] objectForKey:[self settingsKey:name + provider:provider + prefix:prefix]]; +} + ++ (void)saveSetting:(NSString *)name object:(id)object provider:(NSString *)provider prefix:(NSString *)prefix { + [[NSUserDefaults standardUserDefaults] setObject:object forKey:[self settingsKey:name + provider:provider + prefix:prefix]]; +} + ++ (void)removeFromUserDefaultsWithServiceProviderName:(NSString *)provider prefix:(NSString *)prefix { + NSArray *keys = [NSArray arrayWithObjects:@"key", @"secret", @"created", @"duration", @"session", @"attributes", @"renewable", nil]; + for(NSString *name in keys) { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:[OAToken settingsKey:name provider:provider prefix:prefix]]; + } +} + ++ (NSNumber *)durationWithString:(NSString *)aDuration { + NSUInteger length = [aDuration length]; + unichar c = toupper([aDuration characterAtIndex:length - 1]); + int mult; + if (c >= '0' && c <= '9') { + return [NSNumber numberWithInt:[aDuration intValue]]; + } + if (c == 'S') { + mult = 1; + } else if (c == 'H') { + mult = 60 * 60; + } else if (c == 'D') { + mult = 60 * 60 * 24; + } else if (c == 'W') { + mult = 60 * 60 * 24 * 7; + } else if (c == 'M') { + mult = 60 * 60 * 24 * 30; + } else if (c == 'Y') { + mult = 60 * 60 * 365; + } else { + mult = 1; + } + + return [NSNumber numberWithInt: mult * [[aDuration substringToIndex:length - 1] intValue]]; +} + ++ (NSDictionary *)attributesWithString:(NSString *)theAttributes { + NSArray *attrs = [theAttributes componentsSeparatedByString:@";"]; + NSMutableDictionary *dct = [[NSMutableDictionary alloc] init]; + for (NSString *pair in attrs) { + NSArray *elements = [pair componentsSeparatedByString:@":"]; + [dct setObject:[elements objectAtIndex:1] forKey:[elements objectAtIndex:0]]; + } + return [dct autorelease]; +} + +#pragma mark description + +- (NSString *)description { + return [NSString stringWithFormat:@"Key \"%@\" Secret:\"%@\"", key, secret]; +} + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OATokenManager.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OATokenManager.h new file mode 100644 index 0000000..bebfc80 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OATokenManager.h @@ -0,0 +1,68 @@ +// +// OATokenManager.h +// OAuthConsumer +// +// Created by Alberto García Hierro on 01/09/08. +// Copyright 2008 Alberto García Hierro. All rights reserved. +// bynotes.com + +#import + +#import "OACall.h" + +@class OATokenManager; + +@protocol OATokenManagerDelegate + +- (BOOL)tokenManager:(OATokenManager *)manager failedCall:(OACall *)call withError:(NSError *)error; +- (BOOL)tokenManager:(OATokenManager *)manager failedCall:(OACall *)call withProblem:(OAProblem *)problem; + +@optional + +- (BOOL)tokenManagerNeedsToken:(OATokenManager *)manager; + +@end + +@class OAConsumer; +@class OAToken; + +@interface OATokenManager : NSObject { + OAConsumer *consumer; + OAToken *acToken; + OAToken *reqToken; + OAToken *initialToken; + NSString *authorizedTokenKey; + NSString *oauthBase; + NSString *realm; + NSString *callback; + NSObject *delegate; + NSMutableArray *calls; + NSMutableArray *selectors; + NSMutableDictionary *delegates; + BOOL isDispatching; +} + + +- (id)init; + +- (id)initWithConsumer:(OAConsumer *)aConsumer token:(OAToken *)aToken oauthBase:(const NSString *)base + realm:(const NSString *)aRealm callback:(const NSString *)aCallback + delegate:(NSObject *)aDelegate; + +- (void)authorizedToken:(const NSString *)key; + +- (void)fetchData:(NSString *)aURL finished:(SEL)didFinish; + +- (void)fetchData:(NSString *)aURL method:(NSString *)aMethod parameters:(NSArray *)theParameters + finished:(SEL)didFinish; + +- (void)fetchData:(NSString *)aURL method:(NSString *)aMethod parameters:(NSArray *)theParameters + files:(NSDictionary *)theFiles finished:(SEL)didFinish; + +- (void)fetchData:(NSString *)aURL method:(NSString *)aMethod parameters:(NSArray *)theParameters + files:(NSDictionary *)theFiles finished:(SEL)didFinish delegate:(NSObject*)aDelegate; + +- (void)call:(OACall *)call failedWithError:(NSError *)error; +- (void)call:(OACall *)call failedWithProblem:(OAProblem *)problem; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OATokenManager.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OATokenManager.m new file mode 100644 index 0000000..9de1481 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OATokenManager.m @@ -0,0 +1,400 @@ +// +// OATokenManager.m +// OAuthConsumer +// +// Created by Alberto García Hierro on 01/09/08. +// Copyright 2008 Alberto García Hierro. All rights reserved. +// bynotes.com + +#import "OAConsumer.h" +#import "OAToken.h" +#import "OAProblem.h" +#import "OACall.h" +#import "OATokenManager.h" + +@interface OATokenManager (Private) + +- (void)callProblem:(OACall *)call problem:(OAProblem *)problem; +- (void)callError:(OACall *)call error:(NSError *)error; +- (void)callFinished:(OACall *)call body:(NSString *)body; + +- (void)dispatch; +- (void)performCall:(OACall *)aCall; + +- (void)requestToken; +- (void)requestTokenReceived; +- (void)exchangeToken; +- (void)renewToken; +- (void)accessTokenReceived; +- (void)setAccessToken:(OAToken *)token; +- (void)deleteSavedRequestToken; + +- (OACall *)queue; +- (void)enqueue:(OACall *)call selector:(SEL)selector; +- (void)dequeue:(OACall *)call; +- (SEL)getSelector:(OACall *)call; + +@end + +@implementation OATokenManager + +- (id)init { + return [self initWithConsumer:nil + token:nil + oauthBase:nil + realm:nil + callback:nil + delegate:nil]; +} + +- (id)initWithConsumer:(OAConsumer *)aConsumer token:(OAToken *)aToken oauthBase:(const NSString *)base + realm:(const NSString *)aRealm callback:(const NSString *)aCallback + delegate:(NSObject *)aDelegate { + + [super init]; + consumer = [aConsumer retain]; + acToken = nil; + reqToken = nil; + initialToken = [aToken retain]; + authorizedTokenKey = nil; + oauthBase = [base copy]; + realm = [aRealm copy]; + callback = [aCallback copy]; + delegate = aDelegate; + calls = [[NSMutableArray alloc] init]; + selectors = [[NSMutableArray alloc] init]; + delegates = [[NSMutableDictionary alloc] init]; + isDispatching = NO; + + return self; +} + +- (void)dealloc { + [consumer release]; + [acToken release]; + [reqToken release]; + [initialToken release]; + [authorizedTokenKey release]; + [oauthBase release]; + [realm release]; + [callback release]; + [calls release]; + [selectors release]; + [delegates release]; + [super dealloc]; +} + +// The application got a new authorized +// request token and is notifying us +- (void)authorizedToken:(const NSString *)aKey +{ + if (reqToken && [aKey isEqualToString:reqToken.key]) { + [self exchangeToken]; + } else { + [authorizedTokenKey release]; + authorizedTokenKey = [aKey retain]; + } +} + + +// Private functions + +// Deal with problems and errors in calls + +- (void)call:(OACall *)call failedWithProblem:(OAProblem *)problem +{ + /* Always clear the saved request token, just in case */ + [self deleteSavedRequestToken]; + + if ([problem isEqualToProblem:[OAProblem TokenExpired]]) { + /* renewToken checks if it's renewable */ + [self renewToken]; + } else if ([problem isEqualToProblem:[OAProblem TokenNotRenewable]] || + [problem isEqualToProblem:[OAProblem TokenRejected]]) { + /* This token may have been revoked by the user, get a new one + after removing the stored requestToken, since the problem may be in + it */ + [self setAccessToken:nil]; + [self requestToken]; + } else if ([problem isEqualToProblem:[OAProblem NonceUsed]]) { + /* Just repeat this request */ + [self performCall:call]; + } else { + /* Non-recoverable error, tell the delegate and dequeue the call + if appropiate */ + if([delegate tokenManager:self failedCall:call withProblem:problem]) { + [self dequeue:call]; + } + @synchronized(self) { + isDispatching = NO; + } + } +} + +- (void)call:(OACall *)call failedWithError:(NSError *)error +{ + if([delegate tokenManager:self failedCall:call withError:error]) { + [self dequeue:call]; + } + @synchronized(self) { + isDispatching = NO; + } +} + +// When a call finish, notify the delegate +- (void)callFinished:(OACall *)call body:(NSString *)body +{ + SEL selector = [self getSelector:call]; + id deleg = [delegates objectForKey:[NSString stringWithFormat:@"%p", call]]; + if (deleg) { + [deleg performSelector:selector withObject:body]; + [delegates removeObjectForKey:call]; + } else { + [delegate performSelector:selector withObject:body]; + } + @synchronized(self) { + isDispatching = NO; + } + [self dequeue:call]; + [self dispatch]; +} + +- (OACall *)queue { + id obj = nil; + @synchronized(calls) { + if ([calls count]) { + obj = [calls objectAtIndex:0]; + } + } + return obj; +} + +- (void)enqueue:(OACall *)call selector:(SEL)selector { + NSUInteger idx = [calls indexOfObject:call]; + if (idx == NSNotFound) { + @synchronized(calls) { + [calls addObject:call]; + [call release]; + [selectors addObject:NSStringFromSelector(selector)]; + } + } +} + +- (void)dequeue:(OACall *)call { + NSUInteger idx = [calls indexOfObject:call]; + if (idx != NSNotFound) { + @synchronized(calls) { + [calls removeObjectAtIndex:idx]; + [selectors removeObjectAtIndex:idx]; + } + } +} + +- (SEL)getSelector:(OACall *)call +{ + NSUInteger idx = [calls indexOfObject:call]; + if (idx != NSNotFound) { + return NSSelectorFromString([selectors objectAtIndex:idx]); + } + return 0; +} + +// Token management functions + +// Requesting a new token + +// Gets a new token and opens the default +// browser for authorizing it. The application +// is expected to call authorizedToken when it +// gets the authorized token back + +- (void)requestToken +{ + /* Try to load an access token from settings */ + OAToken *atoken = [[[OAToken alloc] initWithUserDefaultsUsingServiceProviderName:oauthBase prefix:[@"access:" stringByAppendingString:realm]] autorelease]; + if (atoken && [atoken isValid]) { + [self setAccessToken:atoken]; + return; + } + /* Try to load a stored requestToken from + settings (useful for iPhone) */ + OAToken *token = [[[OAToken alloc] initWithUserDefaultsUsingServiceProviderName:oauthBase prefix:[@"request:" stringByAppendingString:realm]] autorelease]; + /* iPhone specific, the manager must have got the authorized token before reaching this point */ + NSLog(@"request token in settings %@", token); + if (token && token.key && [authorizedTokenKey isEqualToString:token.key]) { + reqToken = [token retain]; + [self exchangeToken]; + return; + } + if ([delegate respondsToSelector:@selector(tokenManagerNeedsToken:)]) { + if (![delegate tokenManagerNeedsToken:self]) { + return; + } + } + OACall *call = [[OACall alloc] initWithURL:[NSURL URLWithString:[oauthBase stringByAppendingString:@"request_token"]] method:@"POST"]; + [call perform:consumer + token:initialToken + realm:realm + delegate:self + didFinish:@selector(requestTokenReceived:body:)]; + +} + +- (void)requestTokenReceived:(OACall *)call body:(NSString *)body +{ + /* XXX: Check if token != nil */ + NSLog(@"Received request token %@", body); + OAToken *token = [[[OAToken alloc] initWithHTTPResponseBody:body] autorelease]; + if (token) { + [reqToken release]; + reqToken = [token retain]; + + [reqToken storeInUserDefaultsWithServiceProviderName:oauthBase prefix:[@"request:" stringByAppendingString:realm]]; + /* Save the token in case we exit and start again + before the token is authorized (useful for iPhone) */ + NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@authorize?oauth_token=%@&oauth_callback=%@", + oauthBase, token.key, callback]]; +// [[UIApplication sharedApplication] openURL:url]; + + } + [call release]; +} + +// Exchaing a request token for an access token + +// Exchanges the current authorized +// request token for an access token +- (void)exchangeToken +{ + if (!reqToken) { + [self requestToken]; + return; + } + NSURL *url = [NSURL URLWithString:[oauthBase stringByAppendingString:@"access_token"]]; + OACall *call = [[OACall alloc] initWithURL:url method:@"POST"]; + [call perform:consumer + token:reqToken + realm:realm + delegate:self + didFinish:@selector(accessTokenReceived:body:)]; +} + +- (void)accessTokenReceived:(OACall *)call body:(NSString *)body +{ + OAToken *token = [[OAToken alloc] initWithHTTPResponseBody:body]; + [self setAccessToken:token]; +} + +- (void)renewToken { + NSLog(@"Renewing token"); + if (!acToken || ![acToken isRenewable]) { + [self requestToken]; + return; + } + acToken.forRenewal = YES; + NSURL *url = [NSURL URLWithString:[oauthBase stringByAppendingString:@"access_token"]]; + OACall *call = [[OACall alloc] initWithURL:url method:@"POST"]; + [call perform:consumer + token:acToken + realm:realm + delegate:self + didFinish:@selector(accessTokenReceived:body:)]; +} + +- (void)setAccessToken:(OAToken *)token { + /* Remove the stored requestToken which generated + this access token */ + [self deleteSavedRequestToken]; + if (token) { + [acToken release]; + acToken = [token retain]; + [acToken storeInUserDefaultsWithServiceProviderName:oauthBase prefix:[@"access:" stringByAppendingString:realm]]; + @synchronized(self) { + isDispatching = NO; + } + [self dispatch]; + } else { + /* Clear the in-memory and saved access tokens */ + [acToken release]; + acToken = nil; + [OAToken removeFromUserDefaultsWithServiceProviderName:oauthBase prefix:[@"access:" stringByAppendingString:realm]]; + } +} + +- (void)deleteSavedRequestToken { + [OAToken removeFromUserDefaultsWithServiceProviderName:oauthBase prefix:[@"request:" stringByAppendingString:realm]]; + [reqToken release]; + reqToken = nil; +} + +- (void)performCall:(OACall *)aCall { + NSLog(@"Performing call"); + [aCall perform:consumer + token:acToken + realm:realm + delegate:self + didFinish:@selector(callFinished:body:)]; +} + +- (void)dispatch { + OACall *call = [self queue]; + if (!call) { + return; + } + @synchronized(self) { + if (isDispatching) { + return; + } + isDispatching = YES; + } + NSLog(@"Started dispatching"); + if(acToken) { + [self performCall:call]; + } else if(reqToken) { + [self exchangeToken]; + } else { + [self requestToken]; + } +} + +- (void)fetchData:(NSString *)aURL method:(NSString *)aMethod parameters:(NSArray *)theParameters + files:(NSDictionary *)theFiles finished:(SEL)didFinish delegate:(NSObject*)aDelegate { + + OACall *call = [[OACall alloc] initWithURL:[NSURL URLWithString:aURL] + method:aMethod + parameters:theParameters + files:theFiles]; + NSLog(@"Received request for: %@", aURL); + [self enqueue:call selector:didFinish]; + if (aDelegate) { + [delegates setObject:aDelegate forKey:[NSString stringWithFormat:@"%p", call]]; + } + [self dispatch]; +} + +- (void)fetchData:(NSString *)aURL method:(NSString *)aMethod parameters:(NSArray *)theParameters + files:(NSDictionary *)theFiles finished:(SEL)didFinish { + + [self fetchData:aURL method:aMethod parameters:theParameters files:theFiles + finished:didFinish delegate:nil]; +} + + +- (void)fetchData:(NSString *)aURL method:(NSString *)aMethod parameters:(NSArray *)theParameters + finished:(SEL)didFinish { + + [self fetchData:aURL method:aMethod parameters:theParameters files:nil finished:didFinish]; +} + +- (void)fetchData:(NSString *)aURL parameters:(NSArray *)theParameters files:(NSDictionary *)theFiles + finished:(SEL)didFinish { + + [self fetchData:aURL method:@"POST" parameters:theParameters files:theFiles finished:didFinish]; +} + +- (void)fetchData:(NSString *)aURL finished:(SEL)didFinish { + [self fetchData:aURL method:nil parameters:nil files:nil finished:didFinish]; +} + + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAuthConsumer.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAuthConsumer.h new file mode 100644 index 0000000..fc875eb --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/OAuthConsumer/OAuthConsumer.h @@ -0,0 +1,40 @@ +// +// OAuthConsumer.h +// OAuthConsumer +// +// Created by Jon Crosby on 10/19/07. +// Copyright 2007 Kaboomerang LLC. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "OAProblem.h" +#import "OAToken.h" +#import "OAConsumer.h" +#import "OAMutableURLRequest.h" +#import "NSString+URLEncoding.h" +#import "NSMutableURLRequest+Parameters.h" +#import "NSURL+Base.h" +#import "OASignatureProviding.h" +#import "OAHMAC_SHA1SignatureProvider.h" +#import "OAPlaintextSignatureProvider.h" +#import "OARequestParameter.h" +#import "OAServiceTicket.h" +#import "OADataFetcher.h" +#import "OATokenManager.h" \ No newline at end of file diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.h new file mode 100644 index 0000000..71e9907 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.h @@ -0,0 +1,28 @@ +// +// YPAPISample.h +// YelpAPI +// + +#import + +/** + Sample class for accessing the Yelp API V2. + + This class demonstrates the capability of the Yelp API version 2.0 by using the Search API to + query for businesses by a search term and location, and the Business API to query additional + information about the top result from the search query. + + See the Yelp Documentation http://www.yelp.com/developers/documentation for more info. + */ +@interface YPAPISample : NSObject + +/** + Query the Yelp API with a given term and location and displays the progress in the log + + @param term: The term of the search, e.g: dinner + @param location: The location in which the term should be searched for, e.g: San Francisco, CA + */ +- (void)queryTopBusinessInfoForTerm:(NSString *)term location:(NSString *)location completionHandler:(void (^)(NSDictionary *jsonResponse, NSError *error))completionHandler; + + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.m new file mode 100644 index 0000000..9cb5aaa --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.m @@ -0,0 +1,102 @@ +// +// YPAPISample.m +// YelpAPI + +#import "YPAPISample.h" + +/** + Default paths and search terms used in this example + */ +static NSString * const kAPIHost = @"api.yelp.com"; +static NSString * const kSearchPath = @"/v2/search/"; +static NSString * const kBusinessPath = @"/v2/business/"; +static NSString * const kSearchLimit = @"3"; + +@implementation YPAPISample + +#pragma mark - Public + +- (void)queryTopBusinessInfoForTerm:(NSString *)term location:(NSString *)location completionHandler:(void (^)(NSDictionary *topBusinessJSON, NSError *error))completionHandler { + + NSLog(@"Querying the Search API with term \'%@\' and location \'%@'", term, location); + + //Make a first request to get the search results with the passed term and location + NSURLRequest *searchRequest = [self _searchRequestWithTerm:term location:location]; + NSURLSession *session = [NSURLSession sharedSession]; + [[session dataTaskWithRequest:searchRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + + if (!error && httpResponse.statusCode == 200) { + + NSDictionary *searchResponseJSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; + NSArray *businessArray = searchResponseJSON[@"businesses"]; + + if ([businessArray count] > 0) { + NSDictionary *firstBusiness = [businessArray firstObject]; + NSString *firstBusinessID = firstBusiness[@"id"]; + NSLog(@"%lu businesses found, querying business info for the top result: %@", (unsigned long)[businessArray count], firstBusinessID); + + [self queryBusinessInfoForBusinessId:firstBusinessID completionHandler:completionHandler]; + } else { + completionHandler(nil, error); // No business was found + } + } else { + completionHandler(nil, error); // An error happened or the HTTP response is not a 200 OK + } + }] resume]; +} + +- (void)queryBusinessInfoForBusinessId:(NSString *)businessID completionHandler:(void (^)(NSDictionary *topBusinessJSON, NSError *error))completionHandler { + + NSURLSession *session = [NSURLSession sharedSession]; + NSURLRequest *businessInfoRequest = [self _businessInfoRequestForID:businessID]; + [[session dataTaskWithRequest:businessInfoRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + if (!error && httpResponse.statusCode == 200) { + NSDictionary *businessResponseJSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; + + completionHandler(businessResponseJSON, error); + } else { + completionHandler(nil, error); + } + }] resume]; + +} + + +#pragma mark - API Request Builders + +/** + Builds a request to hit the search endpoint with the given parameters. + + @param term The term of the search, e.g: dinner + @param location The location request, e.g: San Francisco, CA + + @return The NSURLRequest needed to perform the search + */ +- (NSURLRequest *)_searchRequestWithTerm:(NSString *)term location:(NSString *)location { + NSDictionary *params = @{ + @"term": term, + @"location": location, + @"limit": kSearchLimit + }; + + return [NSURLRequest requestWithHost:kAPIHost path:kSearchPath params:params]; +} + +/** + Builds a request to hit the business endpoint with the given business ID. + + @param businessID The id of the business for which we request informations + + @return The NSURLRequest needed to query the business info + */ +- (NSURLRequest *)_businessInfoRequestForID:(NSString *)businessID { + + NSString *businessPath = [NSString stringWithFormat:@"%@%@", kBusinessPath, businessID]; + return [NSURLRequest requestWithHost:kAPIHost path:businessPath]; +} + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YelpAPISample-Prefix.pch b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YelpAPISample-Prefix.pch new file mode 100644 index 0000000..9e1d438 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YelpAPISample-Prefix.pch @@ -0,0 +1,10 @@ +// +// Prefix header +// +// The contents of this file are implicitly included at the beginning of every source file. +// + +#ifdef __OBJC__ + #import + #import "NSURLRequest+OAuth.h" +#endif diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/main.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/main.m new file mode 100644 index 0000000..ef6c987 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/main.m @@ -0,0 +1,56 @@ +// +// main.m +// YelpAPISample +// + +#import +#import "YPAPISample.h" + +/** + + This program uses default query terms that are defined in the main method below. + You can change them at any time by modifying the strings or by changing the command line arguments in the product scheme, as explained below: + + You can edit the command line arguments passed to the program by going into Xcode scheme preferences with the shortcut: Cmd + < + or by going to 'Product' > 'Scheme' > 'Edit Scheme' > 'Arguments' + + The default pattern that you have to use is: -term 'the term here' -location 'the location here' + If no arguments are specified, the program will default to the constants defined in the main method. + + Make sure to enter your API credentials in the "NSURLRequest+OAuth.m" file, otherwise none of your requests will work. + */ +int main(int argc, const char * argv[]) { + + @autoreleasepool { + + NSString *defaultTerm = @"dinner"; + NSString *defaultLocation = @"San Francisco, CA"; + + //Get the term and location from the command line if there were any, otherwise assign default values. + NSString *term = [[NSUserDefaults standardUserDefaults] valueForKey:@"term"] ?: defaultTerm; + NSString *location = [[NSUserDefaults standardUserDefaults] valueForKey:@"location"] ?: defaultLocation; + + YPAPISample *APISample = [[YPAPISample alloc] init]; + + dispatch_group_t requestGroup = dispatch_group_create(); + + dispatch_group_enter(requestGroup); + [APISample queryTopBusinessInfoForTerm:term location:location completionHandler:^(NSDictionary *topBusinessJSON, NSError *error) { + + if (error) { + NSLog(@"An error happened during the request: %@", error); + } else if (topBusinessJSON) { + NSLog(@"Top business info: \n %@", topBusinessJSON); + } else { + NSLog(@"No business was found"); + } + + dispatch_group_leave(requestGroup); + }]; + + dispatch_group_wait(requestGroup, DISPATCH_TIME_FOREVER); // This avoids the program exiting before all our asynchronous callbacks have been made. + } + + return 0; +} + diff --git a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m index fa660d0..5c2d8c3 100644 --- a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m +++ b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m @@ -10,6 +10,8 @@ #import "APIManager.h" #import "VegaNomSearchResult.h" #import +#import "NSURLRequest+OAuth.h" +#import "YPAPISample.h" #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) @@ -40,14 +42,17 @@ - (void)viewDidLoad { } --(void)makeNewFourSquareRequestWithSearchTerm: (NSString *)searchTerm callbackBlock: (void(^)())block{ + + +/*-(void)makeNewFourSquareRequestWithSearchTerm: (NSString *)searchTerm callbackBlock: (void(^)())block{ //searchTerm (comes from our parameter) - //url(media=music, term=searchterm) - NSString *urlString = [NSString stringWithFormat:@"https://itunes.apple.com/search?media=music&term=%@", searchTerm]; + //url(query=searchterm) + NSString *urlString = [NSString stringWithFormat:@"https://api.foursquare.com/v2/venues/explore?ll=40.7,-74&query=%@&oauth_token=LBLFB0ZHUZAN1SA4RYQUQ4BT0RB11Z03GZ33D0ZXAFTDXSNV&v=20150922", searchTerm]; + + NSLog(@"%@", urlString); - //https://api.foursquare.com/v2/venues/explore?ll=40.7,-74&query=vegan&oauth_token=LBLFB0ZHUZAN1SA4RYQUQ4BT0RB11Z03GZ33D0ZXAFTDXSNV&v=20150922 //encoded url NSString *encodedString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; @@ -61,22 +66,33 @@ -(void)makeNewFourSquareRequestWithSearchTerm: (NSString *)searchTerm callbackBl //do something with data NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; - //NSLog(@"%@", json); + NSLog(@"%@", json); - NSArray *results = [json objectForKey:@"results"]; + NSDictionary *results = [json objectForKey:@"response"]; self.searchResults = [[NSMutableArray alloc] init]; for (NSDictionary *result in results) { - NSString *venue = [result objectForKey:@"artistName"]; - NSString *distance = [result objectForKey:@"trackName"]; - NSString *address = [result objectForKey:@"artistName"]; - NSString *phone = [result objectForKey:@"trackName"]; - NSString *hours = [result objectForKey:@"artistName"]; + NSDictionary *groups = [result objectForKey:@"groups"]; + NSLog(@"groups: %@", groups); + + NSDictionary *items = [groups objectForKey:@"items"]; + NSDictionary *venueList = [items objectForKey:@"venue"]; + NSDictionary *contact = [venueList objectForKey:@"contact"]; + NSDictionary *location = [venueList objectForKey:@"location"]; + + NSString *venue = [venueList objectForKey:@"name"]; - NSString *avatarURL = [result objectForKey:@"artworkUrl100"]; - UIImage *avatarImage = [APIManager createImageFromString:avatarURL]; + NSString *distance = [location objectForKey:@"distance"]; + + NSArray *addressArray = [venueList objectForKey:@"formattedAddress"]; + NSString *addressLine1 = addressArray[0]; + NSString *addressLine2 = addressArray[1]; + NSString *address = [NSString stringWithFormat:@"%@/n%@", addressLine1, addressLine2]; + + NSString *phone = [contact objectForKey:@"formattedPhone"]; + NSString *twitter = [contact objectForKey:@"twitter"]; VegaNomSearchResult *venueObject = [[VegaNomSearchResult alloc] init]; @@ -84,21 +100,20 @@ -(void)makeNewFourSquareRequestWithSearchTerm: (NSString *)searchTerm callbackBl venueObject.distance = distance; venueObject.address = address; venueObject.phoneNumber = phone; - venueObject.hoursOfOperation = hours; - venueObject.avatar = avatarImage; + venueObject.twitterHandle = twitter; [self.searchResults addObject:venueObject]; } - //NSLog(@"%@", self.searchResults); + NSLog(@"%@", self.searchResults); //executes the block that we're passing to the method block(); } }]; -} +}*/ #pragma mark - CLLocationManagerDelegate methods @@ -132,7 +147,6 @@ -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NS cell.textLabel.text = currentResult.venueName; cell.detailTextLabel.text = currentResult.distance; - cell.imageView.image = currentResult.avatar; return cell; } @@ -145,9 +159,30 @@ -(BOOL)textFieldShouldReturn:(UITextField *)textField{ [self.view endEditing:YES]; //make an api request - [self makeNewFourSquareRequestWithSearchTerm:textField.text callbackBlock:^{ + + NSString *location = @"New York, NY"; + NSString *searchTerms = [NSString stringWithFormat:@"vegan,%@", textField.text]; + + YPAPISample *yelpAPIRequest = [[YPAPISample alloc] init]; + [yelpAPIRequest queryTopBusinessInfoForTerm:searchTerms location:location completionHandler:^(NSDictionary *jsonResponse, NSError *error) { + + if (error) { + + NSLog(@"An error happened during the request: %@", error); + + } else { + + NSLog(@"No business was found"); + + } + [self.tableView reloadData]; }]; + + +// [self makeNewFourSquareRequestWithSearchTerm:textField.text callbackBlock:^{ +// [self.tableView reloadData]; +// }]; return YES; From ea8b988cbb5bc9f5779243dd0799f9b4860363a3 Mon Sep 17 00:00:00 2001 From: Justine Gartner Date: Wed, 23 Sep 2015 22:51:40 -0400 Subject: [PATCH 04/29] Yelp API request is working :) --- .../TalkinToTheNet.xcodeproj/project.pbxproj | 34 ++--- .../YelpAPISample/YPAPISample.m | 1 + .../TalkinToTheNet/YelpAPISample/main.m | 56 -------- .../TalkinToTheNet/vegaNomViewController.m | 124 ++++++++---------- 4 files changed, 71 insertions(+), 144 deletions(-) delete mode 100644 TalkinToTheNet/TalkinToTheNet/YelpAPISample/main.m diff --git a/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj b/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj index 5d899cc..5664a08 100644 --- a/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj +++ b/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj @@ -10,26 +10,26 @@ 6BA440E91BB0DB5700BEC68E /* APIManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA440E81BB0DB5700BEC68E /* APIManager.m */; settings = {ASSET_TAGS = (); }; }; 6BA440EC1BB0DBA700BEC68E /* vegaNomViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA440EB1BB0DBA700BEC68E /* vegaNomViewController.m */; settings = {ASSET_TAGS = (); }; }; 6BA440F21BB0DF3900BEC68E /* VegaNomSearchResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA440F11BB0DF3900BEC68E /* VegaNomSearchResult.m */; settings = {ASSET_TAGS = (); }; }; - 6BC1C0C71BB37D8A00442479 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C09A1BB37D8A00442479 /* main.m */; settings = {ASSET_TAGS = (); }; }; 6BC1C0C81BB37D8A00442479 /* NSURLRequest+OAuth.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C09C1BB37D8A00442479 /* NSURLRequest+OAuth.m */; settings = {ASSET_TAGS = (); }; }; - 6BC1C0C91BB37D8A00442479 /* NSMutableURLRequest+Parameters.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0A01BB37D8A00442479 /* NSMutableURLRequest+Parameters.m */; settings = {ASSET_TAGS = (); }; }; - 6BC1C0CA1BB37D8A00442479 /* NSString+URLEncoding.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0A21BB37D8A00442479 /* NSString+URLEncoding.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0C91BB37D8A00442479 /* NSMutableURLRequest+Parameters.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0A01BB37D8A00442479 /* NSMutableURLRequest+Parameters.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 6BC1C0CA1BB37D8A00442479 /* NSString+URLEncoding.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0A21BB37D8A00442479 /* NSString+URLEncoding.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 6BC1C0CB1BB37D8A00442479 /* NSURL+Base.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0A41BB37D8A00442479 /* NSURL+Base.m */; settings = {ASSET_TAGS = (); }; }; 6BC1C0CC1BB37D8A00442479 /* Base64Transcoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0A61BB37D8A00442479 /* Base64Transcoder.c */; settings = {ASSET_TAGS = (); }; }; 6BC1C0CD1BB37D8A00442479 /* hmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0A81BB37D8A00442479 /* hmac.c */; settings = {ASSET_TAGS = (); }; }; 6BC1C0CE1BB37D8A00442479 /* sha1.c in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0AA1BB37D8A00442479 /* sha1.c */; settings = {ASSET_TAGS = (); }; }; - 6BC1C0CF1BB37D8A00442479 /* OACall.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0AD1BB37D8A00442479 /* OACall.m */; settings = {ASSET_TAGS = (); }; }; - 6BC1C0D01BB37D8A00442479 /* OAConsumer.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0AF1BB37D8A00442479 /* OAConsumer.m */; settings = {ASSET_TAGS = (); }; }; - 6BC1C0D11BB37D8A00442479 /* OADataFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0B11BB37D8A00442479 /* OADataFetcher.m */; settings = {ASSET_TAGS = (); }; }; - 6BC1C0D21BB37D8A00442479 /* OAHMAC_SHA1SignatureProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0B31BB37D8A00442479 /* OAHMAC_SHA1SignatureProvider.m */; settings = {ASSET_TAGS = (); }; }; - 6BC1C0D31BB37D8A00442479 /* OAMutableURLRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0B51BB37D8A00442479 /* OAMutableURLRequest.m */; settings = {ASSET_TAGS = (); }; }; - 6BC1C0D41BB37D8A00442479 /* OAPlaintextSignatureProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0B71BB37D8A00442479 /* OAPlaintextSignatureProvider.m */; settings = {ASSET_TAGS = (); }; }; - 6BC1C0D51BB37D8A00442479 /* OAProblem.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0B91BB37D8A00442479 /* OAProblem.m */; settings = {ASSET_TAGS = (); }; }; - 6BC1C0D61BB37D8A00442479 /* OARequestParameter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0BB1BB37D8A00442479 /* OARequestParameter.m */; settings = {ASSET_TAGS = (); }; }; - 6BC1C0D71BB37D8A00442479 /* OAServiceTicket.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0BD1BB37D8A00442479 /* OAServiceTicket.m */; settings = {ASSET_TAGS = (); }; }; - 6BC1C0D81BB37D8A00442479 /* OAToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0C01BB37D8A00442479 /* OAToken.m */; settings = {ASSET_TAGS = (); }; }; - 6BC1C0D91BB37D8A00442479 /* OATokenManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0C21BB37D8A00442479 /* OATokenManager.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0CF1BB37D8A00442479 /* OACall.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0AD1BB37D8A00442479 /* OACall.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 6BC1C0D01BB37D8A00442479 /* OAConsumer.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0AF1BB37D8A00442479 /* OAConsumer.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 6BC1C0D11BB37D8A00442479 /* OADataFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0B11BB37D8A00442479 /* OADataFetcher.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 6BC1C0D21BB37D8A00442479 /* OAHMAC_SHA1SignatureProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0B31BB37D8A00442479 /* OAHMAC_SHA1SignatureProvider.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 6BC1C0D31BB37D8A00442479 /* OAMutableURLRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0B51BB37D8A00442479 /* OAMutableURLRequest.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 6BC1C0D41BB37D8A00442479 /* OAPlaintextSignatureProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0B71BB37D8A00442479 /* OAPlaintextSignatureProvider.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 6BC1C0D51BB37D8A00442479 /* OAProblem.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0B91BB37D8A00442479 /* OAProblem.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 6BC1C0D61BB37D8A00442479 /* OARequestParameter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0BB1BB37D8A00442479 /* OARequestParameter.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 6BC1C0D71BB37D8A00442479 /* OAServiceTicket.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0BD1BB37D8A00442479 /* OAServiceTicket.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 6BC1C0D81BB37D8A00442479 /* OAToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0C01BB37D8A00442479 /* OAToken.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 6BC1C0D91BB37D8A00442479 /* OATokenManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0C21BB37D8A00442479 /* OATokenManager.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 6BC1C0DA1BB37D8A00442479 /* YPAPISample.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0C61BB37D8A00442479 /* YPAPISample.m */; settings = {ASSET_TAGS = (); }; }; + 6BC1C0DC1BB391B500442479 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6BC1C0DB1BB391B500442479 /* Foundation.framework */; }; 8D7DCD4B1BAF859400A92AD2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D7DCD4A1BAF859400A92AD2 /* main.m */; }; 8D7DCD4E1BAF859400A92AD2 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 8D7DCD4D1BAF859400A92AD2 /* AppDelegate.m */; }; 8D7DCD541BAF859400A92AD2 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8D7DCD521BAF859400A92AD2 /* Main.storyboard */; }; @@ -44,7 +44,6 @@ 6BA440EB1BB0DBA700BEC68E /* vegaNomViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = vegaNomViewController.m; sourceTree = ""; }; 6BA440F01BB0DF3900BEC68E /* VegaNomSearchResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VegaNomSearchResult.h; sourceTree = ""; }; 6BA440F11BB0DF3900BEC68E /* VegaNomSearchResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VegaNomSearchResult.m; sourceTree = ""; }; - 6BC1C09A1BB37D8A00442479 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 6BC1C09B1BB37D8A00442479 /* NSURLRequest+OAuth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURLRequest+OAuth.h"; sourceTree = ""; }; 6BC1C09C1BB37D8A00442479 /* NSURLRequest+OAuth.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURLRequest+OAuth.m"; sourceTree = ""; }; 6BC1C09F1BB37D8A00442479 /* NSMutableURLRequest+Parameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableURLRequest+Parameters.h"; sourceTree = ""; }; @@ -86,6 +85,7 @@ 6BC1C0C41BB37D8A00442479 /* YelpAPISample-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "YelpAPISample-Prefix.pch"; sourceTree = ""; }; 6BC1C0C51BB37D8A00442479 /* YPAPISample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YPAPISample.h; sourceTree = ""; }; 6BC1C0C61BB37D8A00442479 /* YPAPISample.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YPAPISample.m; sourceTree = ""; }; + 6BC1C0DB1BB391B500442479 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 8D7DCD461BAF859400A92AD2 /* TalkinToTheNet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TalkinToTheNet.app; sourceTree = BUILT_PRODUCTS_DIR; }; 8D7DCD4A1BAF859400A92AD2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 8D7DCD4C1BAF859400A92AD2 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; @@ -101,6 +101,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 6BC1C0DC1BB391B500442479 /* Foundation.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -110,7 +111,6 @@ 6BC1C0991BB37D8A00442479 /* YelpAPISample */ = { isa = PBXGroup; children = ( - 6BC1C09A1BB37D8A00442479 /* main.m */, 6BC1C09B1BB37D8A00442479 /* NSURLRequest+OAuth.h */, 6BC1C09C1BB37D8A00442479 /* NSURLRequest+OAuth.m */, 6BC1C09D1BB37D8A00442479 /* OAuthConsumer */, @@ -183,6 +183,7 @@ 8D7DCD3D1BAF859400A92AD2 = { isa = PBXGroup; children = ( + 6BC1C0DB1BB391B500442479 /* Foundation.framework */, 8D7DCD481BAF859400A92AD2 /* TalkinToTheNet */, 8D7DCD471BAF859400A92AD2 /* Products */, ); @@ -315,7 +316,6 @@ 8D7DCD4B1BAF859400A92AD2 /* main.m in Sources */, 6BA440EC1BB0DBA700BEC68E /* vegaNomViewController.m in Sources */, 6BC1C0CC1BB37D8A00442479 /* Base64Transcoder.c in Sources */, - 6BC1C0C71BB37D8A00442479 /* main.m in Sources */, 6BA440E91BB0DB5700BEC68E /* APIManager.m in Sources */, 6BC1C0D01BB37D8A00442479 /* OAConsumer.m in Sources */, 6BC1C0C81BB37D8A00442479 /* NSURLRequest+OAuth.m in Sources */, diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.m index 9cb5aaa..9f48ce9 100644 --- a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.m +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.m @@ -3,6 +3,7 @@ // YelpAPI #import "YPAPISample.h" +#import "NSURLRequest+OAuth.h" /** Default paths and search terms used in this example diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/main.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/main.m deleted file mode 100644 index ef6c987..0000000 --- a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/main.m +++ /dev/null @@ -1,56 +0,0 @@ -// -// main.m -// YelpAPISample -// - -#import -#import "YPAPISample.h" - -/** - - This program uses default query terms that are defined in the main method below. - You can change them at any time by modifying the strings or by changing the command line arguments in the product scheme, as explained below: - - You can edit the command line arguments passed to the program by going into Xcode scheme preferences with the shortcut: Cmd + < - or by going to 'Product' > 'Scheme' > 'Edit Scheme' > 'Arguments' - - The default pattern that you have to use is: -term 'the term here' -location 'the location here' - If no arguments are specified, the program will default to the constants defined in the main method. - - Make sure to enter your API credentials in the "NSURLRequest+OAuth.m" file, otherwise none of your requests will work. - */ -int main(int argc, const char * argv[]) { - - @autoreleasepool { - - NSString *defaultTerm = @"dinner"; - NSString *defaultLocation = @"San Francisco, CA"; - - //Get the term and location from the command line if there were any, otherwise assign default values. - NSString *term = [[NSUserDefaults standardUserDefaults] valueForKey:@"term"] ?: defaultTerm; - NSString *location = [[NSUserDefaults standardUserDefaults] valueForKey:@"location"] ?: defaultLocation; - - YPAPISample *APISample = [[YPAPISample alloc] init]; - - dispatch_group_t requestGroup = dispatch_group_create(); - - dispatch_group_enter(requestGroup); - [APISample queryTopBusinessInfoForTerm:term location:location completionHandler:^(NSDictionary *topBusinessJSON, NSError *error) { - - if (error) { - NSLog(@"An error happened during the request: %@", error); - } else if (topBusinessJSON) { - NSLog(@"Top business info: \n %@", topBusinessJSON); - } else { - NSLog(@"No business was found"); - } - - dispatch_group_leave(requestGroup); - }]; - - dispatch_group_wait(requestGroup, DISPATCH_TIME_FOREVER); // This avoids the program exiting before all our asynchronous callbacks have been made. - } - - return 0; -} - diff --git a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m index 5c2d8c3..7893497 100644 --- a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m +++ b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m @@ -44,76 +44,74 @@ - (void)viewDidLoad { -/*-(void)makeNewFourSquareRequestWithSearchTerm: (NSString *)searchTerm callbackBlock: (void(^)())block{ - - //searchTerm (comes from our parameter) - - //url(query=searchterm) - NSString *urlString = [NSString stringWithFormat:@"https://api.foursquare.com/v2/venues/explore?ll=40.7,-74&query=%@&oauth_token=LBLFB0ZHUZAN1SA4RYQUQ4BT0RB11Z03GZ33D0ZXAFTDXSNV&v=20150922", searchTerm]; - - NSLog(@"%@", urlString); +-(void)makeNewYelpRequestWithSearchTerm: (NSString *)searchTerm callbackBlock: (void(^)())block{ + //make the request - //encoded url - NSString *encodedString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; + NSString *location = @"New York, NY"; + NSString *searchTerms = [NSString stringWithFormat:@"vegan,%@", searchTerm]; - NSURL *url = [NSURL URLWithString:encodedString]; + YPAPISample *yelpAPIRequest = [[YPAPISample alloc] init]; - //make the request - [APIManager GetRequestWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + [yelpAPIRequest queryTopBusinessInfoForTerm:searchTerms location:location completionHandler:^(NSDictionary *jsonResponse, NSError *error) { - if (data != nil) { + if (error) { + NSLog(@"An error happened during the request: %@", error); - //do something with data - NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; - NSLog(@"%@", json); + } else if (jsonResponse) { + NSLog(@"Top business info: \n %@", jsonResponse); - NSDictionary *results = [json objectForKey:@"response"]; + NSDictionary *results = jsonResponse; self.searchResults = [[NSMutableArray alloc] init]; - for (NSDictionary *result in results) { - - NSDictionary *groups = [result objectForKey:@"groups"]; - NSLog(@"groups: %@", groups); - - NSDictionary *items = [groups objectForKey:@"items"]; - NSDictionary *venueList = [items objectForKey:@"venue"]; - NSDictionary *contact = [venueList objectForKey:@"contact"]; - NSDictionary *location = [venueList objectForKey:@"location"]; - - NSString *venue = [venueList objectForKey:@"name"]; - - NSString *distance = [location objectForKey:@"distance"]; - - NSArray *addressArray = [venueList objectForKey:@"formattedAddress"]; - NSString *addressLine1 = addressArray[0]; - NSString *addressLine2 = addressArray[1]; - NSString *address = [NSString stringWithFormat:@"%@/n%@", addressLine1, addressLine2]; - - NSString *phone = [contact objectForKey:@"formattedPhone"]; - NSString *twitter = [contact objectForKey:@"twitter"]; - - VegaNomSearchResult *venueObject = [[VegaNomSearchResult alloc] init]; - - venueObject.venueName = venue; - venueObject.distance = distance; - venueObject.address = address; - venueObject.phoneNumber = phone; - venueObject.twitterHandle = twitter; - - [self.searchResults addObject:venueObject]; - - } +// for (NSDictionary *result in results) { +// +// NSDictionary *groups = [result objectForKey:@"groups"]; +// NSLog(@"groups: %@", groups); +// +// NSDictionary *items = [groups objectForKey:@"items"]; +// NSDictionary *venueList = [items objectForKey:@"venue"]; +// NSDictionary *contact = [venueList objectForKey:@"contact"]; +// NSDictionary *location = [venueList objectForKey:@"location"]; +// +// NSString *venue = [venueList objectForKey:@"name"]; +// +// NSString *distance = [location objectForKey:@"distance"]; +// +// NSArray *addressArray = [venueList objectForKey:@"formattedAddress"]; +// NSString *addressLine1 = addressArray[0]; +// NSString *addressLine2 = addressArray[1]; +// NSString *address = [NSString stringWithFormat:@"%@/n%@", addressLine1, addressLine2]; +// +// NSString *phone = [contact objectForKey:@"formattedPhone"]; +// NSString *twitter = [contact objectForKey:@"twitter"]; +// +// VegaNomSearchResult *venueObject = [[VegaNomSearchResult alloc] init]; +// +// venueObject.venueName = venue; +// venueObject.distance = distance; +// venueObject.address = address; +// venueObject.phoneNumber = phone; +// venueObject.twitterHandle = twitter; +// +// [self.searchResults addObject:venueObject]; + + + } else { + NSLog(@"No business was found"); + } + + }]; + NSLog(@"%@", self.searchResults); //executes the block that we're passing to the method block(); - } - }]; -}*/ + +} #pragma mark - CLLocationManagerDelegate methods @@ -160,25 +158,9 @@ -(BOOL)textFieldShouldReturn:(UITextField *)textField{ //make an api request - NSString *location = @"New York, NY"; - NSString *searchTerms = [NSString stringWithFormat:@"vegan,%@", textField.text]; - - YPAPISample *yelpAPIRequest = [[YPAPISample alloc] init]; - [yelpAPIRequest queryTopBusinessInfoForTerm:searchTerms location:location completionHandler:^(NSDictionary *jsonResponse, NSError *error) { - - if (error) { - - NSLog(@"An error happened during the request: %@", error); - - } else { - - NSLog(@"No business was found"); - - } - + [self makeNewYelpRequestWithSearchTerm:textField.text callbackBlock:^{ [self.tableView reloadData]; }]; - // [self makeNewFourSquareRequestWithSearchTerm:textField.text callbackBlock:^{ // [self.tableView reloadData]; From 8d125ce32d240db1b88fbdce421bd1c118299100 Mon Sep 17 00:00:00 2001 From: Justine Gartner Date: Thu, 24 Sep 2015 18:49:27 -0400 Subject: [PATCH 05/29] working on pulling data from the api now --- .../TalkinToTheNet/VegaNomSearchResult.h | 2 - .../YelpAPISample/YPAPISample.m | 2 +- .../TalkinToTheNet/vegaNomViewController.m | 70 ++++++++++--------- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.h b/TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.h index cbef4ee..e8bbd73 100644 --- a/TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.h +++ b/TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.h @@ -12,10 +12,8 @@ @interface VegaNomSearchResult : NSObject @property (nonatomic) NSString *venueName; -@property (nonatomic) NSString *distance; @property (nonatomic) UIImage *avatar; @property (nonatomic) NSString *address; @property (nonatomic) NSString *phoneNumber; -@property (nonatomic) NSString *twitterHandle; @end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.m index 9f48ce9..79f6e07 100644 --- a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.m +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.m @@ -11,7 +11,7 @@ static NSString * const kAPIHost = @"api.yelp.com"; static NSString * const kSearchPath = @"/v2/search/"; static NSString * const kBusinessPath = @"/v2/business/"; -static NSString * const kSearchLimit = @"3"; +static NSString * const kSearchLimit = @"20"; @implementation YPAPISample diff --git a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m index 7893497..9a7de1a 100644 --- a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m +++ b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m @@ -63,42 +63,43 @@ -(void)makeNewYelpRequestWithSearchTerm: (NSString *)searchTerm callbackBlock: ( NSDictionary *results = jsonResponse; - self.searchResults = [[NSMutableArray alloc] init]; + NSLog(@"jsonResponse dictionary: %@", results); -// for (NSDictionary *result in results) { -// -// NSDictionary *groups = [result objectForKey:@"groups"]; -// NSLog(@"groups: %@", groups); -// -// NSDictionary *items = [groups objectForKey:@"items"]; -// NSDictionary *venueList = [items objectForKey:@"venue"]; -// NSDictionary *contact = [venueList objectForKey:@"contact"]; -// NSDictionary *location = [venueList objectForKey:@"location"]; -// -// NSString *venue = [venueList objectForKey:@"name"]; -// -// NSString *distance = [location objectForKey:@"distance"]; -// -// NSArray *addressArray = [venueList objectForKey:@"formattedAddress"]; -// NSString *addressLine1 = addressArray[0]; -// NSString *addressLine2 = addressArray[1]; -// NSString *address = [NSString stringWithFormat:@"%@/n%@", addressLine1, addressLine2]; -// -// NSString *phone = [contact objectForKey:@"formattedPhone"]; -// NSString *twitter = [contact objectForKey:@"twitter"]; -// -// VegaNomSearchResult *venueObject = [[VegaNomSearchResult alloc] init]; -// -// venueObject.venueName = venue; -// venueObject.distance = distance; -// venueObject.address = address; -// venueObject.phoneNumber = phone; -// venueObject.twitterHandle = twitter; -// -// [self.searchResults addObject:venueObject]; + self.searchResults = [[NSMutableArray alloc] init]; + for (NSDictionary *result in results) { + + NSString *venue = [result objectForKey:@"name"]; + NSLog(@"venuename: %@", venue); + + NSDictionary *location = [result objectForKey:@"location"]; + NSLog(@"location dictionary: %@", location); + + NSArray *addressArray = [location objectForKey:@"display_address"]; + NSString *addressLine1 = addressArray[0]; + NSString *addressLine2 = addressArray[1]; + NSString *addressLine3 = addressArray[2]; + NSString *venueAddress = [NSString stringWithFormat:@"%@ %@ %@", addressLine1, addressLine2, addressLine3]; + + NSLog(@"address: %@", venueAddress); + + NSString *phone = [result objectForKey:@"display_phone"]; + + NSString *venueImage = [result objectForKey:@"image_url"]; + + UIImage *image = [APIManager createImageFromString:venueImage]; + + VegaNomSearchResult *venueObject = [[VegaNomSearchResult alloc] init]; + + venueObject.venueName = venue; + venueObject.address = venueAddress; + venueObject.phoneNumber = phone; + venueObject.avatar = image; + + [self.searchResults addObject:venueObject]; + } - } else { + }else { NSLog(@"No business was found"); } @@ -144,7 +145,8 @@ -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NS VegaNomSearchResult *currentResult = self.searchResults[indexPath.row]; cell.textLabel.text = currentResult.venueName; - cell.detailTextLabel.text = currentResult.distance; + cell.detailTextLabel.text = currentResult.address; + cell.imageView.image = currentResult.avatar; return cell; } From 10e4166af6c91b78191a67d7282b41d4fdebbbaf Mon Sep 17 00:00:00 2001 From: Justine Gartner Date: Thu, 24 Sep 2015 22:41:54 -0400 Subject: [PATCH 06/29] extracting data from Yelp API successfully --- .../YelpAPISample/YPAPISample.h | 2 +- .../YelpAPISample/YPAPISample.m | 7 +++-- .../TalkinToTheNet/vegaNomViewController.m | 31 ++++++++++--------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.h b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.h index 71e9907..12eac5a 100644 --- a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.h +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.h @@ -22,7 +22,7 @@ @param term: The term of the search, e.g: dinner @param location: The location in which the term should be searched for, e.g: San Francisco, CA */ -- (void)queryTopBusinessInfoForTerm:(NSString *)term location:(NSString *)location completionHandler:(void (^)(NSDictionary *jsonResponse, NSError *error))completionHandler; +- (void)queryTopBusinessInfoForTerm:(NSString *)term location:(NSString *)location completionHandler:(void (^)(NSArray *businesses, NSError *error))completionHandler; @end diff --git a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.m b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.m index 79f6e07..2aff1eb 100644 --- a/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.m +++ b/TalkinToTheNet/TalkinToTheNet/YelpAPISample/YPAPISample.m @@ -17,7 +17,7 @@ @implementation YPAPISample #pragma mark - Public -- (void)queryTopBusinessInfoForTerm:(NSString *)term location:(NSString *)location completionHandler:(void (^)(NSDictionary *topBusinessJSON, NSError *error))completionHandler { +- (void)queryTopBusinessInfoForTerm:(NSString *)term location:(NSString *)location completionHandler:(void (^)(NSArray *businesses, NSError *error))completionHandler { NSLog(@"Querying the Search API with term \'%@\' and location \'%@'", term, location); @@ -38,7 +38,10 @@ - (void)queryTopBusinessInfoForTerm:(NSString *)term location:(NSString *)locati NSString *firstBusinessID = firstBusiness[@"id"]; NSLog(@"%lu businesses found, querying business info for the top result: %@", (unsigned long)[businessArray count], firstBusinessID); - [self queryBusinessInfoForBusinessId:firstBusinessID completionHandler:completionHandler]; + dispatch_async(dispatch_get_main_queue(), ^{ + completionHandler(businessArray, nil); + }); +// [self queryBusinessInfoForBusinessId:firstBusinessID completionHandler:completionHandler]; } else { completionHandler(nil, error); // No business was found } diff --git a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m index 9a7de1a..3022be4 100644 --- a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m +++ b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m @@ -53,26 +53,26 @@ -(void)makeNewYelpRequestWithSearchTerm: (NSString *)searchTerm callbackBlock: ( YPAPISample *yelpAPIRequest = [[YPAPISample alloc] init]; - [yelpAPIRequest queryTopBusinessInfoForTerm:searchTerms location:location completionHandler:^(NSDictionary *jsonResponse, NSError *error) { + [yelpAPIRequest queryTopBusinessInfoForTerm:searchTerms location:location completionHandler:^(NSArray *businesses, NSError *error) { if (error) { NSLog(@"An error happened during the request: %@", error); - } else if (jsonResponse) { - NSLog(@"Top business info: \n %@", jsonResponse); + } else if (businesses) { + NSLog(@"Top business info: \n %@", businesses); - NSDictionary *results = jsonResponse; + NSArray *result = businesses; - NSLog(@"jsonResponse dictionary: %@", results); + NSLog(@"jsonResponse dictionary: %@", result); self.searchResults = [[NSMutableArray alloc] init]; - for (NSDictionary *result in results) { + for (NSDictionary *business in businesses) { - NSString *venue = [result objectForKey:@"name"]; + NSString *venue = [business objectForKey:@"name"]; NSLog(@"venuename: %@", venue); - NSDictionary *location = [result objectForKey:@"location"]; + NSDictionary *location = [business objectForKey:@"location"]; NSLog(@"location dictionary: %@", location); NSArray *addressArray = [location objectForKey:@"display_address"]; @@ -83,12 +83,12 @@ -(void)makeNewYelpRequestWithSearchTerm: (NSString *)searchTerm callbackBlock: ( NSLog(@"address: %@", venueAddress); - NSString *phone = [result objectForKey:@"display_phone"]; + NSString *phone = [business objectForKey:@"display_phone"]; - NSString *venueImage = [result objectForKey:@"image_url"]; + NSString *venueImage = [business objectForKey:@"image_url"]; UIImage *image = [APIManager createImageFromString:venueImage]; - + VegaNomSearchResult *venueObject = [[VegaNomSearchResult alloc] init]; venueObject.venueName = venue; @@ -97,6 +97,10 @@ -(void)makeNewYelpRequestWithSearchTerm: (NSString *)searchTerm callbackBlock: ( venueObject.avatar = image; [self.searchResults addObject:venueObject]; + + NSLog(@"%@", self.searchResults); + + block(); } }else { @@ -104,12 +108,9 @@ -(void)makeNewYelpRequestWithSearchTerm: (NSString *)searchTerm callbackBlock: ( } }]; - - - NSLog(@"%@", self.searchResults); //executes the block that we're passing to the method - block(); +// block(); } From 4fda4dba63bb1ae8ecdae074a0caeeab2336f5af Mon Sep 17 00:00:00 2001 From: Justine Gartner Date: Fri, 25 Sep 2015 18:16:41 -0400 Subject: [PATCH 07/29] Segue to InstagramDetailViewController is working with api request :) --- .../TalkinToTheNet.xcodeproj/project.pbxproj | 18 +++ TalkinToTheNet/TalkinToTheNet/APIManager.h | 4 + TalkinToTheNet/TalkinToTheNet/APIManager.m | 29 ++++ .../TalkinToTheNet/Base.lproj/Main.storyboard | 133 ++++++++++++++++-- TalkinToTheNet/TalkinToTheNet/InstaPost.h | 22 +++ TalkinToTheNet/TalkinToTheNet/InstaPost.m | 34 +++++ .../InstagramDetailViewController.h | 19 +++ .../InstagramDetailViewController.m | 90 ++++++++++++ .../InstagramPostsTableViewCell.h | 18 +++ .../InstagramPostsTableViewCell.m | 23 +++ .../TalkinToTheNet/vegaNomViewController.m | 39 +++-- 11 files changed, 396 insertions(+), 33 deletions(-) create mode 100644 TalkinToTheNet/TalkinToTheNet/InstaPost.h create mode 100644 TalkinToTheNet/TalkinToTheNet/InstaPost.m create mode 100644 TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.h create mode 100644 TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.m create mode 100644 TalkinToTheNet/TalkinToTheNet/InstagramPostsTableViewCell.h create mode 100644 TalkinToTheNet/TalkinToTheNet/InstagramPostsTableViewCell.m diff --git a/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj b/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj index 5664a08..4b41e1b 100644 --- a/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj +++ b/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 6B7BFDE41BB5E7F20014B24E /* InstagramPostsTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B7BFDE31BB5E7F20014B24E /* InstagramPostsTableViewCell.m */; settings = {ASSET_TAGS = (); }; }; + 6B7BFDE71BB5E83C0014B24E /* InstaPost.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B7BFDE61BB5E83C0014B24E /* InstaPost.m */; settings = {ASSET_TAGS = (); }; }; + 6B7BFDEA1BB5E8A30014B24E /* InstagramDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B7BFDE91BB5E8A30014B24E /* InstagramDetailViewController.m */; settings = {ASSET_TAGS = (); }; }; 6BA440E91BB0DB5700BEC68E /* APIManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA440E81BB0DB5700BEC68E /* APIManager.m */; settings = {ASSET_TAGS = (); }; }; 6BA440EC1BB0DBA700BEC68E /* vegaNomViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA440EB1BB0DBA700BEC68E /* vegaNomViewController.m */; settings = {ASSET_TAGS = (); }; }; 6BA440F21BB0DF3900BEC68E /* VegaNomSearchResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA440F11BB0DF3900BEC68E /* VegaNomSearchResult.m */; settings = {ASSET_TAGS = (); }; }; @@ -38,6 +41,12 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 6B7BFDE21BB5E7F20014B24E /* InstagramPostsTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InstagramPostsTableViewCell.h; sourceTree = ""; }; + 6B7BFDE31BB5E7F20014B24E /* InstagramPostsTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InstagramPostsTableViewCell.m; sourceTree = ""; }; + 6B7BFDE51BB5E83C0014B24E /* InstaPost.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InstaPost.h; sourceTree = ""; }; + 6B7BFDE61BB5E83C0014B24E /* InstaPost.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InstaPost.m; sourceTree = ""; }; + 6B7BFDE81BB5E8A30014B24E /* InstagramDetailViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InstagramDetailViewController.h; sourceTree = ""; }; + 6B7BFDE91BB5E8A30014B24E /* InstagramDetailViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InstagramDetailViewController.m; sourceTree = ""; }; 6BA440E71BB0DB5700BEC68E /* APIManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIManager.h; sourceTree = ""; }; 6BA440E81BB0DB5700BEC68E /* APIManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APIManager.m; sourceTree = ""; }; 6BA440EA1BB0DBA700BEC68E /* vegaNomViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vegaNomViewController.h; sourceTree = ""; }; @@ -203,6 +212,12 @@ 6BC1C0991BB37D8A00442479 /* YelpAPISample */, 8D7DCD4C1BAF859400A92AD2 /* AppDelegate.h */, 8D7DCD4D1BAF859400A92AD2 /* AppDelegate.m */, + 6B7BFDE51BB5E83C0014B24E /* InstaPost.h */, + 6B7BFDE61BB5E83C0014B24E /* InstaPost.m */, + 6B7BFDE81BB5E8A30014B24E /* InstagramDetailViewController.h */, + 6B7BFDE91BB5E8A30014B24E /* InstagramDetailViewController.m */, + 6B7BFDE21BB5E7F20014B24E /* InstagramPostsTableViewCell.h */, + 6B7BFDE31BB5E7F20014B24E /* InstagramPostsTableViewCell.m */, 6BA440F01BB0DF3900BEC68E /* VegaNomSearchResult.h */, 6BA440F11BB0DF3900BEC68E /* VegaNomSearchResult.m */, 6BA440E71BB0DB5700BEC68E /* APIManager.h */, @@ -300,6 +315,7 @@ 6BC1C0DA1BB37D8A00442479 /* YPAPISample.m in Sources */, 6BC1C0D81BB37D8A00442479 /* OAToken.m in Sources */, 6BC1C0CE1BB37D8A00442479 /* sha1.c in Sources */, + 6B7BFDEA1BB5E8A30014B24E /* InstagramDetailViewController.m in Sources */, 6BC1C0D41BB37D8A00442479 /* OAPlaintextSignatureProvider.m in Sources */, 6BC1C0CD1BB37D8A00442479 /* hmac.c in Sources */, 6BC1C0CA1BB37D8A00442479 /* NSString+URLEncoding.m in Sources */, @@ -310,12 +326,14 @@ 6BC1C0D51BB37D8A00442479 /* OAProblem.m in Sources */, 6BC1C0D11BB37D8A00442479 /* OADataFetcher.m in Sources */, 8D7DCD4E1BAF859400A92AD2 /* AppDelegate.m in Sources */, + 6B7BFDE41BB5E7F20014B24E /* InstagramPostsTableViewCell.m in Sources */, 6BC1C0C91BB37D8A00442479 /* NSMutableURLRequest+Parameters.m in Sources */, 6BC1C0D21BB37D8A00442479 /* OAHMAC_SHA1SignatureProvider.m in Sources */, 6BC1C0D91BB37D8A00442479 /* OATokenManager.m in Sources */, 8D7DCD4B1BAF859400A92AD2 /* main.m in Sources */, 6BA440EC1BB0DBA700BEC68E /* vegaNomViewController.m in Sources */, 6BC1C0CC1BB37D8A00442479 /* Base64Transcoder.c in Sources */, + 6B7BFDE71BB5E83C0014B24E /* InstaPost.m in Sources */, 6BA440E91BB0DB5700BEC68E /* APIManager.m in Sources */, 6BC1C0D01BB37D8A00442479 /* OAConsumer.m in Sources */, 6BC1C0C81BB37D8A00442479 /* NSURLRequest+OAuth.m in Sources */, diff --git a/TalkinToTheNet/TalkinToTheNet/APIManager.h b/TalkinToTheNet/TalkinToTheNet/APIManager.h index 80c242b..f33ddc3 100644 --- a/TalkinToTheNet/TalkinToTheNet/APIManager.h +++ b/TalkinToTheNet/TalkinToTheNet/APIManager.h @@ -16,4 +16,8 @@ + (UIImage *)createImageFromString:(NSString *)urlString; ++ (NSString *)createAddressFromArray: (NSArray *)addressArray; + ++ (NSString *)createTagFromVenueName: (NSString *)venueName; + @end diff --git a/TalkinToTheNet/TalkinToTheNet/APIManager.m b/TalkinToTheNet/TalkinToTheNet/APIManager.m index 9b30f56..e680f4a 100644 --- a/TalkinToTheNet/TalkinToTheNet/APIManager.m +++ b/TalkinToTheNet/TalkinToTheNet/APIManager.m @@ -53,5 +53,34 @@ + (UIImage *)createImageFromString:(NSString *)urlString{ } ++ (NSString *)createAddressFromArray: (NSArray *)addressArray{ + + NSString *venueAddress; + + if (addressArray.count == 3) { + + venueAddress = [NSString stringWithFormat:@"%@ %@ %@", addressArray[0], addressArray[1], addressArray[2]]; + + }else if (addressArray.count == 2){ + + venueAddress = [NSString stringWithFormat:@"%@ %@", addressArray[0], addressArray[1]]; + }else{ + + venueAddress = addressArray[0]; + + } + + return venueAddress; +} + ++ (NSString *)createTagFromVenueName: (NSString *)venueName{ + + NSString *venueNameNoSpaces = [venueName stringByReplacingOccurrencesOfString:@" " withString:@""]; + + NSString *venueTag = [venueNameNoSpaces lowercaseString]; + + return venueTag; +} + @end diff --git a/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard b/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard index ee89742..a8f2686 100644 --- a/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard +++ b/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard @@ -17,12 +17,12 @@ - + - + @@ -31,29 +31,32 @@ - + - + - + + + @@ -82,6 +85,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TalkinToTheNet/TalkinToTheNet/InstaPost.h b/TalkinToTheNet/TalkinToTheNet/InstaPost.h new file mode 100644 index 0000000..1d62882 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/InstaPost.h @@ -0,0 +1,22 @@ +// +// InstaPost.h +// CustomTableViewCells +// +// Created by Justine Gartner on 9/24/15. +// Copyright © 2015 Justine Gartner. All rights reserved. +// + +#import + +@interface InstaPost : NSObject + +@property (nonatomic) NSArray *tags; +@property (nonatomic) NSInteger commentCount; +@property (nonatomic) NSInteger likeCount; +@property (nonatomic) NSString *username; +@property (nonatomic) NSString *fullName; +@property (nonatomic) NSDictionary *caption; + +-(instancetype)initWithJSON: (NSDictionary *)json; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/InstaPost.m b/TalkinToTheNet/TalkinToTheNet/InstaPost.m new file mode 100644 index 0000000..8ea8600 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/InstaPost.m @@ -0,0 +1,34 @@ +// +// InstaPost.m +// CustomTableViewCells +// +// Created by Justine Gartner on 9/24/15. +// Copyright © 2015 Justine Gartner. All rights reserved. +// + +#import "InstaPost.h" + +@implementation InstaPost + +-(instancetype)initWithJSON: (NSDictionary *)json{ + + //call super init, return self + + if (self = [super init]){ + + self.tags = [json objectForKey:@"tags"]; + self.commentCount = [json[@"comments"][@"count"]integerValue]; + self.likeCount = [json[@"likes"][@"count"]integerValue]; + + self.username = json[@"user"][@"username"]; + self.fullName = json[@"user"][@"full_name"]; + self.caption = json[@"caption"]; + + return self; + + } + return nil; + +} + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.h b/TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.h new file mode 100644 index 0000000..8e939c5 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.h @@ -0,0 +1,19 @@ +// +// InstagramDetailViewController.h +// TalkinToTheNet +// +// Created by Justine Gartner on 9/25/15. +// Copyright © 2015 Mike Kavouras. All rights reserved. +// + +#import +#import "InstaPost.h" +#import "InstagramPostsTableViewCell.h" + +@interface InstagramDetailViewController : UIViewController + +@property (nonatomic) NSString *venueNameTag; + + + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.m b/TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.m new file mode 100644 index 0000000..ba43153 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.m @@ -0,0 +1,90 @@ +// +// InstagramDetailViewController.m +// TalkinToTheNet +// +// Created by Justine Gartner on 9/25/15. +// Copyright © 2015 Mike Kavouras. All rights reserved. +// + +#import "InstagramDetailViewController.h" +#import "APIManager.h" + +@interface InstagramDetailViewController () + +@property (weak, nonatomic) IBOutlet UILabel *tagLabel; +@property (weak, nonatomic) IBOutlet UITableView *tableView; + +@property (nonatomic) NSMutableArray *searchResults; + +@end + +@implementation InstagramDetailViewController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.tableView.delegate = self; + self.tableView.dataSource = self; + + self.tagLabel.text = [NSString stringWithFormat:@"#%@ on Instagram", self.venueNameTag]; + + [self fetchInstagramData]; + +} + +-(void)fetchInstagramData{ + + NSString *venueNameTagURL = [NSString stringWithFormat:@"https://api.instagram.com/v1/tags/%@/media/recent?client_id=ac0ee52ebb154199bfabfb15b498c067", self.venueNameTag]; + + NSURL *instagramURL = [NSURL URLWithString:venueNameTagURL]; + + [APIManager GetRequestWithURL:instagramURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; + + NSArray *results = json[@"data"]; + + self.searchResults = [[NSMutableArray alloc] init]; + + for (NSDictionary *result in results){ + + InstaPost *post = [[InstaPost alloc] initWithJSON:result]; + + [self.searchResults addObject:post]; + } + + NSLog(@"%@", json); + + [self.tableView reloadData]; + + }]; + +} + +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + + return self.searchResults.count; +} + + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + + InstagramPostsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"InstaPostCellIdentifier" forIndexPath:indexPath]; + + InstaPost *post = self.searchResults[indexPath.row]; + + cell.usernameLabel.text = post.username; + cell.likesLabel.text = [NSString stringWithFormat:@"Likes: %ld",post.likeCount]; + cell.captionLabel.text = post.caption[@"text"]; + + return cell; +} + + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/InstagramPostsTableViewCell.h b/TalkinToTheNet/TalkinToTheNet/InstagramPostsTableViewCell.h new file mode 100644 index 0000000..b07f30e --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/InstagramPostsTableViewCell.h @@ -0,0 +1,18 @@ +// +// InstagramPostsTableViewCell.h +// TalkinToTheNet +// +// Created by Justine Gartner on 9/25/15. +// Copyright © 2015 Mike Kavouras. All rights reserved. +// + +#import + +@interface InstagramPostsTableViewCell : UITableViewCell +@property (weak, nonatomic) IBOutlet UIImageView *instaPostImageView; + +@property (weak, nonatomic) IBOutlet UILabel *usernameLabel; +@property (weak, nonatomic) IBOutlet UILabel *captionLabel; +@property (weak, nonatomic) IBOutlet UILabel *likesLabel; + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/InstagramPostsTableViewCell.m b/TalkinToTheNet/TalkinToTheNet/InstagramPostsTableViewCell.m new file mode 100644 index 0000000..c0e1c30 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/InstagramPostsTableViewCell.m @@ -0,0 +1,23 @@ +// +// InstagramPostsTableViewCell.m +// TalkinToTheNet +// +// Created by Justine Gartner on 9/25/15. +// Copyright © 2015 Mike Kavouras. All rights reserved. +// + +#import "InstagramPostsTableViewCell.h" + +@implementation InstagramPostsTableViewCell + +- (void)awakeFromNib { + // Initialization code +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated { + [super setSelected:selected animated:animated]; + + // Configure the view for the selected state +} + +@end diff --git a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m index 3022be4..63877da 100644 --- a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m +++ b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m @@ -12,6 +12,8 @@ #import #import "NSURLRequest+OAuth.h" #import "YPAPISample.h" +#import "InstagramDetailViewController.h" +#import "InstaPost.h" #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) @@ -37,17 +39,12 @@ - (void)viewDidLoad { self.whereTextField.delegate = self; self.locationManager.delegate = self; - //[self.locationManager requestLocation]; - //[self.locationManager startUpdatingLocation]; - } -(void)makeNewYelpRequestWithSearchTerm: (NSString *)searchTerm callbackBlock: (void(^)())block{ - //make the request - NSString *location = @"New York, NY"; NSString *searchTerms = [NSString stringWithFormat:@"vegan,%@", searchTerm]; @@ -76,10 +73,8 @@ -(void)makeNewYelpRequestWithSearchTerm: (NSString *)searchTerm callbackBlock: ( NSLog(@"location dictionary: %@", location); NSArray *addressArray = [location objectForKey:@"display_address"]; - NSString *addressLine1 = addressArray[0]; - NSString *addressLine2 = addressArray[1]; - NSString *addressLine3 = addressArray[2]; - NSString *venueAddress = [NSString stringWithFormat:@"%@ %@ %@", addressLine1, addressLine2, addressLine3]; + + NSString *venueAddress = [APIManager createAddressFromArray:addressArray]; NSLog(@"address: %@", venueAddress); @@ -108,10 +103,6 @@ -(void)makeNewYelpRequestWithSearchTerm: (NSString *)searchTerm callbackBlock: ( } }]; - - //executes the block that we're passing to the method -// block(); - } @@ -165,23 +156,25 @@ -(BOOL)textFieldShouldReturn:(UITextField *)textField{ [self.tableView reloadData]; }]; -// [self makeNewFourSquareRequestWithSearchTerm:textField.text callbackBlock:^{ -// [self.tableView reloadData]; -// }]; - - return YES; } -/* + #pragma mark - Navigation -// In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { - // Get the new view controller using [segue destinationViewController]. - // Pass the selected object to the new view controller. + + NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; + + VegaNomSearchResult *currentResult = self.searchResults [indexPath.row]; + + NSString *currentResultTagName = [APIManager createTagFromVenueName:currentResult.venueName]; + + InstagramDetailViewController *detailViewController = segue.destinationViewController; + + detailViewController.venueNameTag = currentResultTagName; + } -*/ @end From 073914b715a42346f5d2c5d7f060287f9df9ed32 Mon Sep 17 00:00:00 2001 From: Justine Gartner Date: Fri, 25 Sep 2015 19:42:40 -0400 Subject: [PATCH 08/29] Images loading on InstagramDetailViewController --- TalkinToTheNet/TalkinToTheNet/InstaPost.h | 2 ++ TalkinToTheNet/TalkinToTheNet/InstaPost.m | 5 +++++ .../TalkinToTheNet/InstagramDetailViewController.m | 2 ++ 3 files changed, 9 insertions(+) diff --git a/TalkinToTheNet/TalkinToTheNet/InstaPost.h b/TalkinToTheNet/TalkinToTheNet/InstaPost.h index 1d62882..41b9659 100644 --- a/TalkinToTheNet/TalkinToTheNet/InstaPost.h +++ b/TalkinToTheNet/TalkinToTheNet/InstaPost.h @@ -7,6 +7,7 @@ // #import +#import @interface InstaPost : NSObject @@ -16,6 +17,7 @@ @property (nonatomic) NSString *username; @property (nonatomic) NSString *fullName; @property (nonatomic) NSDictionary *caption; +@property (nonatomic) UIImage *instaImage; -(instancetype)initWithJSON: (NSDictionary *)json; diff --git a/TalkinToTheNet/TalkinToTheNet/InstaPost.m b/TalkinToTheNet/TalkinToTheNet/InstaPost.m index 8ea8600..f2c851f 100644 --- a/TalkinToTheNet/TalkinToTheNet/InstaPost.m +++ b/TalkinToTheNet/TalkinToTheNet/InstaPost.m @@ -7,6 +7,7 @@ // #import "InstaPost.h" +#import "APIManager.h" @implementation InstaPost @@ -24,6 +25,10 @@ -(instancetype)initWithJSON: (NSDictionary *)json{ self.fullName = json[@"user"][@"full_name"]; self.caption = json[@"caption"]; + NSString *imageURLString = json[@"images"][@"low_resolution"][@"url"]; + UIImage *image = [APIManager createImageFromString:imageURLString]; + self.instaImage = image; + return self; } diff --git a/TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.m b/TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.m index ba43153..d9002dc 100644 --- a/TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.m +++ b/TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.m @@ -83,6 +83,8 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell.likesLabel.text = [NSString stringWithFormat:@"Likes: %ld",post.likeCount]; cell.captionLabel.text = post.caption[@"text"]; + cell.imageView.image = post.instaImage; + return cell; } From 3fd019fbdb965a22485e096c4ca6ecec8b5fe0af Mon Sep 17 00:00:00 2001 From: Justine Gartner Date: Fri, 25 Sep 2015 20:30:33 -0400 Subject: [PATCH 09/29] added Instagram logo to InstagramDetailViewController --- .../Assets.xcassets/Contents.json | 6 +++ .../Instagram.imageset/Contents.json | 21 +++++++++++ .../Instagram.imageset/Instagram.jpg | Bin 0 -> 7724 bytes .../Instagram_logo.imageset/Contents.json | 21 +++++++++++ .../Instagram_logo.png | Bin 0 -> 33754 bytes .../Contents.json | 12 ++++++ .../instagram_wordmark_detail.gif | Bin 0 -> 19280 bytes .../TalkinToTheNet/Base.lproj/Main.storyboard | 35 +++++++++++++++--- .../InstagramDetailViewController.m | 5 ++- 9 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 TalkinToTheNet/TalkinToTheNet/Assets.xcassets/Contents.json create mode 100644 TalkinToTheNet/TalkinToTheNet/Assets.xcassets/Instagram.imageset/Contents.json create mode 100644 TalkinToTheNet/TalkinToTheNet/Assets.xcassets/Instagram.imageset/Instagram.jpg create mode 100644 TalkinToTheNet/TalkinToTheNet/Assets.xcassets/Instagram_logo.imageset/Contents.json create mode 100644 TalkinToTheNet/TalkinToTheNet/Assets.xcassets/Instagram_logo.imageset/Instagram_logo.png create mode 100644 TalkinToTheNet/TalkinToTheNet/Assets.xcassets/instagram_wordmark_detail.dataset/Contents.json create mode 100644 TalkinToTheNet/TalkinToTheNet/Assets.xcassets/instagram_wordmark_detail.dataset/instagram_wordmark_detail.gif diff --git a/TalkinToTheNet/TalkinToTheNet/Assets.xcassets/Contents.json b/TalkinToTheNet/TalkinToTheNet/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/TalkinToTheNet/TalkinToTheNet/Assets.xcassets/Instagram.imageset/Contents.json b/TalkinToTheNet/TalkinToTheNet/Assets.xcassets/Instagram.imageset/Contents.json new file mode 100644 index 0000000..b814470 --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/Assets.xcassets/Instagram.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "Instagram.jpg", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/TalkinToTheNet/TalkinToTheNet/Assets.xcassets/Instagram.imageset/Instagram.jpg b/TalkinToTheNet/TalkinToTheNet/Assets.xcassets/Instagram.imageset/Instagram.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bbaca4814e13a3a5b90edb34a839d0d691a8ac8d GIT binary patch literal 7724 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 literal 0 HcmV?d00001 diff --git a/TalkinToTheNet/TalkinToTheNet/Assets.xcassets/Instagram_logo.imageset/Contents.json b/TalkinToTheNet/TalkinToTheNet/Assets.xcassets/Instagram_logo.imageset/Contents.json new file mode 100644 index 0000000..20ceefb --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/Assets.xcassets/Instagram_logo.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Instagram_logo.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/TalkinToTheNet/TalkinToTheNet/Assets.xcassets/Instagram_logo.imageset/Instagram_logo.png b/TalkinToTheNet/TalkinToTheNet/Assets.xcassets/Instagram_logo.imageset/Instagram_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9916b60dbe57a95f423c201a870ea47a9839f8ea GIT binary patch literal 33754 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 KMNUMnLSTYZxa9u; literal 0 HcmV?d00001 diff --git a/TalkinToTheNet/TalkinToTheNet/Assets.xcassets/instagram_wordmark_detail.dataset/Contents.json b/TalkinToTheNet/TalkinToTheNet/Assets.xcassets/instagram_wordmark_detail.dataset/Contents.json new file mode 100644 index 0000000..18b623f --- /dev/null +++ b/TalkinToTheNet/TalkinToTheNet/Assets.xcassets/instagram_wordmark_detail.dataset/Contents.json @@ -0,0 +1,12 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "data" : [ + { + "idiom" : "universal", + "filename" : "instagram_wordmark_detail.gif" + } + ] +} \ No newline at end of file diff --git a/TalkinToTheNet/TalkinToTheNet/Assets.xcassets/instagram_wordmark_detail.dataset/instagram_wordmark_detail.gif b/TalkinToTheNet/TalkinToTheNet/Assets.xcassets/instagram_wordmark_detail.dataset/instagram_wordmark_detail.gif new file mode 100644 index 0000000000000000000000000000000000000000..0337c7a4f68f9e14bcc0d3a3d74f4403ae1550ec GIT binary patch literal 19280 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 S{Tg;`*|TZawtahKKma@C7MPX* literal 0 HcmV?d00001 diff --git a/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard b/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard index a8f2686..f53702c 100644 --- a/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard +++ b/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard @@ -100,20 +100,41 @@ - + - - + + + + + + + + + + + + @@ -139,7 +160,7 @@ - + @@ -212,4 +234,7 @@ + + + diff --git a/TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.m b/TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.m index d9002dc..4ecaac3 100644 --- a/TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.m +++ b/TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.m @@ -13,6 +13,7 @@ @interface InstagramDetailViewController () Date: Fri, 25 Sep 2015 21:56:33 -0400 Subject: [PATCH 10/29] readjusting the ui in the InstagramDetailViewController --- TalkinToTheNet/TalkinToTheNet/APIManager.m | 23 +++---- .../TalkinToTheNet/Base.lproj/Main.storyboard | 66 +++++++++++-------- TalkinToTheNet/TalkinToTheNet/InstaPost.m | 1 + .../InstagramDetailViewController.h | 2 - .../InstagramPostsTableViewCell.h | 2 +- .../InstagramPostsTableViewCell.m | 10 --- .../TalkinToTheNet/VegaNomSearchResult.h | 1 - .../TalkinToTheNet/vegaNomViewController.m | 16 +---- 8 files changed, 51 insertions(+), 70 deletions(-) diff --git a/TalkinToTheNet/TalkinToTheNet/APIManager.m b/TalkinToTheNet/TalkinToTheNet/APIManager.m index e680f4a..cd91b58 100644 --- a/TalkinToTheNet/TalkinToTheNet/APIManager.m +++ b/TalkinToTheNet/TalkinToTheNet/APIManager.m @@ -10,24 +10,14 @@ @implementation APIManager - -//we make this a class method + -//because the method is stateless. -//this way we don't have to initialize objects to use it - + (void)GetRequestWithURL: (NSURL *)url completionHandler: (void(^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler { - //CREATING REQUEST: - - //create session NSURLSession *session = [NSURLSession sharedSession]; - //create task + NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { - //NSLog(@"%@", data); - dispatch_async(dispatch_get_main_queue(), ^{ completionHandler(data, response, error); @@ -35,8 +25,6 @@ + (void)GetRequestWithURL: (NSURL *)url }); }]; - //PERFORMING REQUEST: - [task resume]; } @@ -75,9 +63,14 @@ + (NSString *)createAddressFromArray: (NSArray *)addressArray{ + (NSString *)createTagFromVenueName: (NSString *)venueName{ - NSString *venueNameNoSpaces = [venueName stringByReplacingOccurrencesOfString:@" " withString:@""]; + NSString *venueNameApostrophe = [venueName stringByReplacingOccurrencesOfString:@"'" withString:@""]; + NSString *vNameAmpersand = [venueNameApostrophe stringByReplacingOccurrencesOfString:@"&" withString:@"and"]; + NSString *vNameDash = [vNameAmpersand stringByReplacingOccurrencesOfString:@"-" withString:@""]; + NSString *vNameE = [vNameDash stringByReplacingOccurrencesOfString:@"é" withString:@"e"]; + NSString *venueNameNoSpaces = [vNameE stringByReplacingOccurrencesOfString:@" " withString:@""]; + NSString *babycakesBakery = [venueNameNoSpaces stringByReplacingOccurrencesOfString:@"ErinMcKennasBabyCakes" withString:@"erinmckennasbakery"]; - NSString *venueTag = [venueNameNoSpaces lowercaseString]; + NSString *venueTag = [babycakesBakery lowercaseString]; return venueTag; } diff --git a/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard b/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard index f53702c..c229587 100644 --- a/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard +++ b/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard @@ -100,43 +100,55 @@ - - - + + + + + + + + + + + - + + + - - - + + + + + + + + + + + - + + - - - - - - - - + + + + + + - - - - - - + diff --git a/TalkinToTheNet/TalkinToTheNet/InstaPost.m b/TalkinToTheNet/TalkinToTheNet/InstaPost.m index f2c851f..1bf1ffa 100644 --- a/TalkinToTheNet/TalkinToTheNet/InstaPost.m +++ b/TalkinToTheNet/TalkinToTheNet/InstaPost.m @@ -32,6 +32,7 @@ -(instancetype)initWithJSON: (NSDictionary *)json{ return self; } + return nil; } diff --git a/TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.h b/TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.h index 8e939c5..85ea471 100644 --- a/TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.h +++ b/TalkinToTheNet/TalkinToTheNet/InstagramDetailViewController.h @@ -14,6 +14,4 @@ @property (nonatomic) NSString *venueNameTag; - - @end diff --git a/TalkinToTheNet/TalkinToTheNet/InstagramPostsTableViewCell.h b/TalkinToTheNet/TalkinToTheNet/InstagramPostsTableViewCell.h index b07f30e..aa19966 100644 --- a/TalkinToTheNet/TalkinToTheNet/InstagramPostsTableViewCell.h +++ b/TalkinToTheNet/TalkinToTheNet/InstagramPostsTableViewCell.h @@ -9,8 +9,8 @@ #import @interface InstagramPostsTableViewCell : UITableViewCell -@property (weak, nonatomic) IBOutlet UIImageView *instaPostImageView; +@property (weak, nonatomic) IBOutlet UIImageView *instaPostImageView; @property (weak, nonatomic) IBOutlet UILabel *usernameLabel; @property (weak, nonatomic) IBOutlet UILabel *captionLabel; @property (weak, nonatomic) IBOutlet UILabel *likesLabel; diff --git a/TalkinToTheNet/TalkinToTheNet/InstagramPostsTableViewCell.m b/TalkinToTheNet/TalkinToTheNet/InstagramPostsTableViewCell.m index c0e1c30..89d50e6 100644 --- a/TalkinToTheNet/TalkinToTheNet/InstagramPostsTableViewCell.m +++ b/TalkinToTheNet/TalkinToTheNet/InstagramPostsTableViewCell.m @@ -10,14 +10,4 @@ @implementation InstagramPostsTableViewCell -- (void)awakeFromNib { - // Initialization code -} - -- (void)setSelected:(BOOL)selected animated:(BOOL)animated { - [super setSelected:selected animated:animated]; - - // Configure the view for the selected state -} - @end diff --git a/TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.h b/TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.h index e8bbd73..96b03b3 100644 --- a/TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.h +++ b/TalkinToTheNet/TalkinToTheNet/VegaNomSearchResult.h @@ -14,6 +14,5 @@ @property (nonatomic) NSString *venueName; @property (nonatomic) UIImage *avatar; @property (nonatomic) NSString *address; -@property (nonatomic) NSString *phoneNumber; @end diff --git a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m index 63877da..162d6c3 100644 --- a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m +++ b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m @@ -22,6 +22,8 @@ @interface vegaNomViewController () Date: Fri, 25 Sep 2015 22:25:21 -0400 Subject: [PATCH 11/29] must enter both search term and city,state to get results --- .../TalkinToTheNet/vegaNomViewController.m | 51 ++++++++++++++++--- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m index 162d6c3..25e5c05 100644 --- a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m +++ b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m @@ -22,6 +22,8 @@ @interface vegaNomViewController () Date: Fri, 25 Sep 2015 22:51:10 -0400 Subject: [PATCH 12/29] moved the UIAlertController into the makeYelpRequest.. method --- .../TalkinToTheNet/vegaNomViewController.m | 60 +++++++------------ 1 file changed, 21 insertions(+), 39 deletions(-) diff --git a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m index 25e5c05..90bacc3 100644 --- a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m +++ b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m @@ -49,7 +49,6 @@ - (void)viewDidLoad { -(void)makeNewYelpRequestWithSearchTerm: (NSString *)searchTerm andLocation: (NSString *)location callbackBlock: (void(^)())block{ - //NSString *location = @"New York, NY"; NSString *searchTerms = [NSString stringWithFormat:@"vegan,%@", searchTerm]; YPAPISample *yelpAPIRequest = [[YPAPISample alloc] init]; @@ -90,6 +89,20 @@ -(void)makeNewYelpRequestWithSearchTerm: (NSString *)searchTerm andLocation: (NS }else { NSLog(@"No business was found"); + + UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"No businesses found." + message:@"Please be sure to enter a city and state" + preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault + handler:^(UIAlertAction * action) {}]; + + [alert addAction:defaultAction]; + alert.view.tintColor = [UIColor orangeColor]; + + [self presentViewController:alert animated:YES completion:nil]; + + } }]; @@ -140,48 +153,17 @@ -(BOOL)textFieldShouldReturn:(UITextField *)textField{ //dismiss keyboard [self.view endEditing:YES]; - - if (self.whatTextField.text == nil || self.whereTextField.text == nil) { - - UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Oops!" - message:@"Please enter a search term" - preferredStyle:UIAlertControllerStyleAlert]; - - UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault - handler:^(UIAlertAction * action) {}]; - - [alert addAction:defaultAction]; - alert.view.tintColor = [UIColor yellowColor]; - - [self presentViewController:alert animated:YES completion:nil]; - - [self makeNewYelpRequestWithSearchTerm:self.searchTerm andLocation: self.location callbackBlock:^{ - [self.tableView reloadData]; - }]; - - - }else if (self.whereTextField.text == nil){ - - self.searchTerm = self.whatTextField.text; - self.location = @"NewYork, NY"; - - [self makeNewYelpRequestWithSearchTerm:self.searchTerm andLocation: self.location callbackBlock:^{ - [self.tableView reloadData]; - }]; + self.searchTerm = self.whatTextField.text; + self.location = self.whereTextField.text; - }else{ - - self.searchTerm = self.whatTextField.text; - self.location = self.whereTextField.text; + [self makeNewYelpRequestWithSearchTerm:self.searchTerm andLocation: self.location callbackBlock:^{ - [self makeNewYelpRequestWithSearchTerm:self.searchTerm andLocation: self.location callbackBlock:^{ - [self.tableView reloadData]; - }]; + [self.tableView reloadData]; - } - - + self.searchTerm = nil; + self.location = nil; + }]; return YES; } From adf09c70601792f4eca7ac9251633f73248c1196 Mon Sep 17 00:00:00 2001 From: Justine Gartner Date: Sat, 26 Sep 2015 10:21:12 -0400 Subject: [PATCH 13/29] added new fonts --- .../TalkinToTheNet.xcodeproj/project.pbxproj | 8 ++++ TalkinToTheNet/TalkinToTheNet/AppDelegate.m | 12 ++++- .../TalkinToTheNet/Base.lproj/Main.storyboard | 44 +++++++++++------- TalkinToTheNet/TalkinToTheNet/DistProTh.otf | Bin 0 -> 103760 bytes .../FreightSansCmpPro-Light.otf | Bin 0 -> 96424 bytes TalkinToTheNet/TalkinToTheNet/Info.plist | 5 ++ .../TalkinToTheNet/vegaNomViewController.m | 4 +- 7 files changed, 54 insertions(+), 19 deletions(-) create mode 100644 TalkinToTheNet/TalkinToTheNet/DistProTh.otf create mode 100644 TalkinToTheNet/TalkinToTheNet/FreightSansCmpPro-Light.otf diff --git a/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj b/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj index 4b41e1b..f3b2f0d 100644 --- a/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj +++ b/TalkinToTheNet/TalkinToTheNet.xcodeproj/project.pbxproj @@ -13,6 +13,8 @@ 6BA440E91BB0DB5700BEC68E /* APIManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA440E81BB0DB5700BEC68E /* APIManager.m */; settings = {ASSET_TAGS = (); }; }; 6BA440EC1BB0DBA700BEC68E /* vegaNomViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA440EB1BB0DBA700BEC68E /* vegaNomViewController.m */; settings = {ASSET_TAGS = (); }; }; 6BA440F21BB0DF3900BEC68E /* VegaNomSearchResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BA440F11BB0DF3900BEC68E /* VegaNomSearchResult.m */; settings = {ASSET_TAGS = (); }; }; + 6BA4F96C1BB6DE7300497B07 /* DistProTh.otf in Resources */ = {isa = PBXBuildFile; fileRef = 6BA4F96A1BB6DCFA00497B07 /* DistProTh.otf */; }; + 6BA4F96D1BB6DE7B00497B07 /* FreightSansCmpPro-Light.otf in Resources */ = {isa = PBXBuildFile; fileRef = 6BA4F96B1BB6DD1200497B07 /* FreightSansCmpPro-Light.otf */; }; 6BC1C0C81BB37D8A00442479 /* NSURLRequest+OAuth.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C09C1BB37D8A00442479 /* NSURLRequest+OAuth.m */; settings = {ASSET_TAGS = (); }; }; 6BC1C0C91BB37D8A00442479 /* NSMutableURLRequest+Parameters.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0A01BB37D8A00442479 /* NSMutableURLRequest+Parameters.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 6BC1C0CA1BB37D8A00442479 /* NSString+URLEncoding.m in Sources */ = {isa = PBXBuildFile; fileRef = 6BC1C0A21BB37D8A00442479 /* NSString+URLEncoding.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; @@ -53,6 +55,8 @@ 6BA440EB1BB0DBA700BEC68E /* vegaNomViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = vegaNomViewController.m; sourceTree = ""; }; 6BA440F01BB0DF3900BEC68E /* VegaNomSearchResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VegaNomSearchResult.h; sourceTree = ""; }; 6BA440F11BB0DF3900BEC68E /* VegaNomSearchResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VegaNomSearchResult.m; sourceTree = ""; }; + 6BA4F96A1BB6DCFA00497B07 /* DistProTh.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = DistProTh.otf; sourceTree = ""; }; + 6BA4F96B1BB6DD1200497B07 /* FreightSansCmpPro-Light.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "FreightSansCmpPro-Light.otf"; sourceTree = ""; }; 6BC1C09B1BB37D8A00442479 /* NSURLRequest+OAuth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURLRequest+OAuth.h"; sourceTree = ""; }; 6BC1C09C1BB37D8A00442479 /* NSURLRequest+OAuth.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURLRequest+OAuth.m"; sourceTree = ""; }; 6BC1C09F1BB37D8A00442479 /* NSMutableURLRequest+Parameters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableURLRequest+Parameters.h"; sourceTree = ""; }; @@ -236,6 +240,8 @@ 8D7DCD491BAF859400A92AD2 /* Supporting Files */ = { isa = PBXGroup; children = ( + 6BA4F96A1BB6DCFA00497B07 /* DistProTh.otf */, + 6BA4F96B1BB6DD1200497B07 /* FreightSansCmpPro-Light.otf */, 8D7DCD4A1BAF859400A92AD2 /* main.m */, ); name = "Supporting Files"; @@ -298,6 +304,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 6BA4F96D1BB6DE7B00497B07 /* FreightSansCmpPro-Light.otf in Resources */, + 6BA4F96C1BB6DE7300497B07 /* DistProTh.otf in Resources */, 8D7DCD591BAF859400A92AD2 /* LaunchScreen.storyboard in Resources */, 8D7DCD561BAF859400A92AD2 /* Assets.xcassets in Resources */, 8D7DCD541BAF859400A92AD2 /* Main.storyboard in Resources */, diff --git a/TalkinToTheNet/TalkinToTheNet/AppDelegate.m b/TalkinToTheNet/TalkinToTheNet/AppDelegate.m index d99b336..f420697 100644 --- a/TalkinToTheNet/TalkinToTheNet/AppDelegate.m +++ b/TalkinToTheNet/TalkinToTheNet/AppDelegate.m @@ -16,7 +16,17 @@ @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - // Override point for customization after application launch. + + for (NSString* family in [UIFont familyNames]) + { + NSLog(@"%@", family); + + for (NSString* name in [UIFont fontNamesForFamilyName: family]) + { + NSLog(@" %@", name); + } + } + return YES; } diff --git a/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard b/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard index c229587..42961e5 100644 --- a/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard +++ b/TalkinToTheNet/TalkinToTheNet/Base.lproj/Main.storyboard @@ -4,6 +4,16 @@ + + + DistrictPro-Thin + + + FreightSansCmpPro-Light + FreightSansCmpPro-Light + FreightSansCmpPro-Light + + @@ -42,14 +52,14 @@ - + @@ -110,7 +120,7 @@ - + @@ -120,14 +130,14 @@ - - + @@ -135,7 +145,7 @@ - + @@ -166,22 +176,22 @@ - - + - - + + - - - - - - + + + + + @@ -176,20 +184,20 @@ - diff --git a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m index 89be67f..dbd45cb 100644 --- a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m +++ b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m @@ -18,10 +18,13 @@ #import #import #import +#import "MapKit/MapKit.h" #define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) @interface vegaNomViewController () + +@property (weak, nonatomic) IBOutlet MKMapView *mapView; @property (weak, nonatomic) IBOutlet UITableView *tableView; @property (weak, nonatomic) IBOutlet UITextField *whatTextField; @property (weak, nonatomic) IBOutlet UITextField *whereTextField; @@ -38,6 +41,13 @@ @implementation vegaNomViewController - (void)viewDidLoad { [super viewDidLoad]; + //start with map centered at the following coordinates + //with a span from the center point + CLLocationCoordinate2D center = CLLocationCoordinate2DMake(40.7, -74); + MKCoordinateSpan span = MKCoordinateSpanMake(0.8, 0.8); + + [self.mapView setRegion:MKCoordinateRegionMake(center, span) animated:YES]; + self.locationManager = [[CLLocationManager alloc] init]; if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) { From d0794ac8a09536431382a833039ee9cdbc71ae3a Mon Sep 17 00:00:00 2001 From: Justine Gartner Date: Fri, 2 Oct 2015 02:20:37 -0400 Subject: [PATCH 25/29] map view is fully functioning --- TalkinToTheNet/TalkinToTheNet/APIManager.m | 3 +- .../TalkinToTheNet/vegaNomViewController.m | 65 ++++++++++++++++--- 2 files changed, 59 insertions(+), 9 deletions(-) diff --git a/TalkinToTheNet/TalkinToTheNet/APIManager.m b/TalkinToTheNet/TalkinToTheNet/APIManager.m index d580e2d..8934384 100644 --- a/TalkinToTheNet/TalkinToTheNet/APIManager.m +++ b/TalkinToTheNet/TalkinToTheNet/APIManager.m @@ -122,8 +122,9 @@ + (NSString *)createTagFromVenueName: (NSString *)venueName{ NSString *vNameBabyCakesBakery = [vNameSpaces stringByReplacingOccurrencesOfString:@"ErinMcKennasBabyCakes" withString:@"erinmckennasbakery"]; NSString *vNameExclamation = [vNameBabyCakesBakery stringByReplacingOccurrencesOfString:@"!" withString:@""]; NSString *vNameI = [vNameExclamation stringByReplacingOccurrencesOfString:@"í" withString:@"i"]; + NSString *vNamePeriod = [vNameI stringByReplacingOccurrencesOfString:@"." withString:@""]; - NSString *venueTag = [vNameI lowercaseString]; + NSString *venueTag = [vNamePeriod lowercaseString]; return venueTag; } diff --git a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m index dbd45cb..e461932 100644 --- a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m +++ b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m @@ -14,7 +14,6 @@ #import "NSURLRequest+OAuth.h" #import "InstagramDetailViewController.h" #import "InstaPost.h" -//#import "NYAlertViewController.h" #import #import #import @@ -29,6 +28,7 @@ @interface vegaNomViewController () Date: Fri, 2 Oct 2015 03:02:58 -0400 Subject: [PATCH 26/29] added navigationItem title, added CLLocationManager method getLocation --- .../TalkinToTheNet/vegaNomViewController.m | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m index e461932..2c1489e 100644 --- a/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m +++ b/TalkinToTheNet/TalkinToTheNet/vegaNomViewController.m @@ -46,10 +46,14 @@ - (void)viewDidLoad { self.whatTextField.delegate = self; self.whereTextField.delegate = self; self.locationManager.delegate = self; + self.navigationItem.title = @"VegaNom"; //start with map centered at the following coordinates //with a span from the center point - CLLocationCoordinate2D center = CLLocationCoordinate2DMake(40.7, -74); + + //CLLocationCoordinate2D center = [self getLocation]; + + CLLocationCoordinate2D center = CLLocationCoordinate2DMake(40.7, -74); //for running in the simulator MKCoordinateSpan span = MKCoordinateSpanMake(0.25, 0.25); [self.mapView setRegion:MKCoordinateRegionMake(center, span) animated:YES]; @@ -62,6 +66,18 @@ - (void)viewDidLoad { } +-(CLLocationCoordinate2D) getLocation{ + CLLocationManager *locationManager = [[CLLocationManager alloc] init]; + locationManager.delegate = self; + locationManager.desiredAccuracy = kCLLocationAccuracyBest; + locationManager.distanceFilter = kCLDistanceFilterNone; + [locationManager startUpdatingLocation]; + CLLocation *location = [locationManager location]; + CLLocationCoordinate2D coordinate = [location coordinate]; + + return coordinate; +} + -(void)makeNewYelpRequestWithSearchTerm: (NSString *)searchTerm andLocation: (NSString *)location callbackBlock: (void(^)())block{ @@ -112,7 +128,7 @@ -(void)presentAlertViewForNoLocation{ [self setUpCustomAlertViewController:alertViewController withTitle:@"Oops" - message:@"Please enter a valid city and state." + message:@"Please enter a valid address, city and/or state." andAction:@"OK"]; [self presentViewController:alertViewController animated:YES completion:nil]; From 1ea923f2bb61ca35c15b1e289c33a05273a1ed46 Mon Sep 17 00:00:00 2001 From: JustineKay Date: Sun, 20 Dec 2015 16:57:16 -0500 Subject: [PATCH 27/29] Update README.md --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0c0341f..9dbea65 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,11 @@ -# unit-2-hw-1 +# Vegan Om Nom Nom -Welcome to the world of places. +###Description +Search for Vegan businesses using the Yelp API. +View location on a mapview. +View posts with the #restaurantName using the Instagram API. + +Originated from class assignment: Unit-2-hw-1 (See requirements below.) ### Objective Using either the **[Foursquare API](https://developer.foursquare.com)** or the **[Yelp API](https://www.yelp.com/developers/documentation/v2/overview)**, fetch a list of places near a specific location. @@ -10,7 +15,6 @@ Your application should also provide the ability to view additional data (catego **The interesting part** On the detail page, your application must provide one additional piece of information provided by another api. For example, fetch the number of Twitter followers based on their twitter handle. Or pull instagram pictures based on the category of the venue. -I'll update this with some screens. ### Ideas > **Twitter** From 724dcfe8ccbb27ab9ed8a780b0071afa56b6e0b5 Mon Sep 17 00:00:00 2001 From: JustineKay Date: Sun, 20 Dec 2015 18:18:17 -0500 Subject: [PATCH 28/29] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9dbea65..ee2438d 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ Search for Vegan businesses using the Yelp API. View location on a mapview. View posts with the #restaurantName using the Instagram API. -Originated from class assignment: Unit-2-hw-1 (See requirements below.) +Originated from class assignment: -### Objective +### Unit-2-hw-1 Objective Using either the **[Foursquare API](https://developer.foursquare.com)** or the **[Yelp API](https://www.yelp.com/developers/documentation/v2/overview)**, fetch a list of places near a specific location. Your application should also provide the ability to view additional data (category, address, avatar, etc) From ef24f41d84040d6cec0d8f464dcdd36abf5273c5 Mon Sep 17 00:00:00 2001 From: JustineKay Date: Sun, 20 Dec 2015 18:21:53 -0500 Subject: [PATCH 29/29] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ee2438d..7a2ba66 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,10 @@ Search for Vegan businesses using the Yelp API. View location on a mapview. View posts with the #restaurantName using the Instagram API. -Originated from class assignment: + -### Unit-2-hw-1 Objective +#### Originated from class assignment, unit-2-hw-1: +#####Objective Using either the **[Foursquare API](https://developer.foursquare.com)** or the **[Yelp API](https://www.yelp.com/developers/documentation/v2/overview)**, fetch a list of places near a specific location. Your application should also provide the ability to view additional data (category, address, avatar, etc)