diff --git a/Example/SimpleAuth/Providers.plist b/Example/SimpleAuth/Providers.plist
index efa2451..6c4aa1c 100644
--- a/Example/SimpleAuth/Providers.plist
+++ b/Example/SimpleAuth/Providers.plist
@@ -19,5 +19,6 @@
trello-web
box-web
onedrive-web
+ dribbble
diff --git a/Example/SimpleAuth/SADAppDelegate.m b/Example/SimpleAuth/SADAppDelegate.m
index 98a5cb2..362f506 100644
--- a/Example/SimpleAuth/SADAppDelegate.m
+++ b/Example/SimpleAuth/SADAppDelegate.m
@@ -88,6 +88,9 @@ - (void)configureAuthorizaionProviders {
// client_id and client_secret are required
SimpleAuth.configuration[@"onedrive-web"] = @{};
+
+ // client_id and client_secret are required
+ SimpleAuth.configuration[@"dribbble"] = @{};
}
diff --git a/Pod/Providers/Dribbble/SimpleAuthDribbbleLoginViewController.h b/Pod/Providers/Dribbble/SimpleAuthDribbbleLoginViewController.h
new file mode 100644
index 0000000..43d5336
--- /dev/null
+++ b/Pod/Providers/Dribbble/SimpleAuthDribbbleLoginViewController.h
@@ -0,0 +1,13 @@
+//
+// SimpleAuthDribbbleLoginViewController.h
+// SimpleAuth
+//
+// Created by Martin Pilch on 21/4/15.
+// Copyright (c) 2015 Martin Pilch, All rights reserved.
+//
+
+#import "SimpleAuthWebViewController.h"
+
+@interface SimpleAuthDribbbleLoginViewController : SimpleAuthWebViewController
+
+@end
diff --git a/Pod/Providers/Dribbble/SimpleAuthDribbbleLoginViewController.m b/Pod/Providers/Dribbble/SimpleAuthDribbbleLoginViewController.m
new file mode 100644
index 0000000..edeed23
--- /dev/null
+++ b/Pod/Providers/Dribbble/SimpleAuthDribbbleLoginViewController.m
@@ -0,0 +1,37 @@
+//
+// SimpleAuthDribbbleLoginViewController.m
+// SimpleAuthInstagram
+//
+// Created by Martin Pilch on 21/4/15.
+// Copyright (c) 2015 Martin Pilch, All rights reserved.
+//
+
+#import "SimpleAuthDribbbleLoginViewController.h"
+
+@implementation SimpleAuthDribbbleLoginViewController
+
+#pragma mark - SimpleAuthWebViewController
+
+- (instancetype)initWithOptions:(NSDictionary *)options requestToken:(NSDictionary *)requestToken {
+ if ((self = [super initWithOptions:options requestToken:requestToken])) {
+ self.title = @"Dribbble";
+ }
+ return self;
+}
+
+- (NSURLRequest *)initialRequest {
+ NSMutableDictionary *parameters = [NSMutableDictionary new];
+ parameters[@"client_id"] = self.options[@"client_id"];
+ parameters[@"redirect_uri"] = self.options[SimpleAuthRedirectURIKey];
+ if (self.options[@"scope"]) {
+ parameters[@"scope"] = [self.options[@"scope"] componentsJoinedByString:@" "];
+ }
+ NSString *URLString = [NSString stringWithFormat:
+ @"https://dribbble.com/oauth/authorize?%@",
+ [CMDQueryStringSerialization queryStringWithDictionary:parameters]];
+ NSURL *URL = [NSURL URLWithString:URLString];
+
+ return [NSURLRequest requestWithURL:URL];
+}
+
+@end
diff --git a/Pod/Providers/Dribbble/SimpleAuthDribbbleProvider.h b/Pod/Providers/Dribbble/SimpleAuthDribbbleProvider.h
new file mode 100644
index 0000000..1ca32c2
--- /dev/null
+++ b/Pod/Providers/Dribbble/SimpleAuthDribbbleProvider.h
@@ -0,0 +1,13 @@
+//
+// SimpleAuthDribbbleProvider.h
+// SimpleAuth
+//
+// Created by Martin Pilch on 21/4/15.
+// Copyright (c) 2015 Martin Pilch, All rights reserved.
+//
+
+#import "SimpleAuthProvider.h"
+
+@interface SimpleAuthDribbbleProvider : SimpleAuthProvider
+
+@end
diff --git a/Pod/Providers/Dribbble/SimpleAuthDribbbleProvider.m b/Pod/Providers/Dribbble/SimpleAuthDribbbleProvider.m
new file mode 100644
index 0000000..52e144d
--- /dev/null
+++ b/Pod/Providers/Dribbble/SimpleAuthDribbbleProvider.m
@@ -0,0 +1,206 @@
+//
+// SimpleAuthDribbbleProvider.m
+// SimpleAuth
+//
+// Created by Martin Pilch on 21/4/15.
+// Copyright (c) 2015 Martin Pilch, All rights reserved.
+//
+
+#import "SimpleAuthDribbbleProvider.h"
+#import "SimpleAuthDribbbleLoginViewController.h"
+
+#import "UIViewController+SimpleAuthAdditions.h"
+#import
+
+@implementation SimpleAuthDribbbleProvider
+
+#pragma mark - SimpleAuthProvider
+
++ (NSString *)type {
+ return @"dribbble";
+}
+
++ (NSDictionary *)defaultOptions {
+
+ // Default present block
+ SimpleAuthInterfaceHandler presentBlock = ^(UIViewController *controller) {
+ UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:controller];
+ navigation.modalPresentationStyle = UIModalPresentationFormSheet;
+ UIViewController *presented = [UIViewController SimpleAuth_presentedViewController];
+ [presented presentViewController:navigation animated:YES completion:nil];
+ };
+
+ // Default dismiss block
+ SimpleAuthInterfaceHandler dismissBlock = ^(id controller) {
+ [controller dismissViewControllerAnimated:YES completion:nil];
+ };
+
+ NSMutableDictionary *options = [NSMutableDictionary dictionaryWithDictionary:[super defaultOptions]];
+ options[SimpleAuthPresentInterfaceBlockKey] = presentBlock;
+ options[SimpleAuthDismissInterfaceBlockKey] = dismissBlock;
+ options[SimpleAuthRedirectURIKey] = @"http://";
+
+ return options;
+}
+
+
+- (void)authorizeWithCompletion:(SimpleAuthRequestHandler)completion {
+ [[[self accessToken]
+ flattenMap:^(id responseObject) {
+ NSArray *signals = @[
+ [self accountWithAccessToken:responseObject],
+ [RACSignal return:responseObject]
+ ];
+ return [self rac_liftSelector:@selector(dictionaryWithAccount:accessToken:) withSignalsFromArray:signals];
+ }]
+ subscribeNext:^(id responseObject) {
+ completion(responseObject, nil);
+ }
+ error:^(NSError *error) {
+ completion(nil, error);
+ }];
+}
+
+#pragma mark - Private
+
+- (RACSignal *)authorizationCode {
+ return [RACSignal createSignal:^RACDisposable *(id subscriber) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ SimpleAuthDribbbleLoginViewController *login = [[SimpleAuthDribbbleLoginViewController alloc] initWithOptions:self.options];
+ login.completion = ^(UIViewController *login, NSURL *URL, NSError *error) {
+ SimpleAuthInterfaceHandler dismissBlock = self.options[SimpleAuthDismissInterfaceBlockKey];
+ dismissBlock(login);
+
+ // Parse URL
+ NSString *fragment = [URL query];
+ NSDictionary *dictionary = [CMDQueryStringSerialization dictionaryWithQueryString:fragment];
+ NSString *code = dictionary[@"code"];
+
+ // Check for error
+ if (![code length]) {
+ [subscriber sendError:error];
+ return;
+ }
+
+ // Send completion
+ [subscriber sendNext:code];
+ [subscriber sendCompleted];
+ };
+
+ SimpleAuthInterfaceHandler block = self.options[SimpleAuthPresentInterfaceBlockKey];
+ block(login);
+ });
+ return nil;
+ }];
+}
+
+
+- (RACSignal *)accessTokenWithAuthorizationCode:(NSString *)code {
+ return [RACSignal createSignal:^RACDisposable *(id subscriber) {
+
+ // Build request
+ NSDictionary *parameters = @{
+ @"code" : code,
+ @"client_id" : self.options[@"client_id"],
+ @"client_secret" : self.options[@"client_secret"],
+ @"redirect_uri" : self.options[SimpleAuthRedirectURIKey],
+ };
+ NSString *query = [CMDQueryStringSerialization queryStringWithDictionary:parameters];
+ NSURL *URL = [NSURL URLWithString:@"https://dribbble.com/oauth/token"];
+ NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
+ request.HTTPMethod = @"POST";
+ request.HTTPBody = [query dataUsingEncoding:NSUTF8StringEncoding];
+
+ // Run request
+ [NSURLConnection sendAsynchronousRequest:request queue:self.operationQueue
+ completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
+ NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 99)];
+ NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
+ if ([indexSet containsIndex:statusCode] && data) {
+ NSError *parseError = nil;
+ NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&parseError];
+ if (dictionary) {
+ [subscriber sendNext:dictionary];
+ [subscriber sendCompleted];
+ }
+ else {
+ [subscriber sendError:parseError];
+ }
+ }
+ else {
+ [subscriber sendError:connectionError];
+ }
+ }];
+
+ return nil;
+ }];
+}
+
+
+- (RACSignal *)accessToken {
+ return [[self authorizationCode] flattenMap:^(id responseObject) {
+ return [self accessTokenWithAuthorizationCode:responseObject];
+ }];
+}
+
+- (RACSignal *)accountWithAccessToken:(NSDictionary *)accessToken {
+ return [RACSignal createSignal:^RACDisposable *(id subscriber) {
+ NSDictionary *parameters = @{
+ @"access_token" : accessToken[@"access_token"],
+ };
+ NSString *URLString = [NSString stringWithFormat:@"https://api.dribbble.com/v1/user?%@",
+ [CMDQueryStringSerialization queryStringWithDictionary:parameters]];
+ NSURL *URL = [NSURL URLWithString:URLString];
+ NSURLRequest *request = [NSURLRequest requestWithURL:URL];
+ [NSURLConnection sendAsynchronousRequest:request queue:self.operationQueue
+ completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
+ NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 99)];
+ NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
+ if ([indexSet containsIndex:statusCode] && data) {
+ NSError *parseError = nil;
+ NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&parseError];
+ if (dictionary) {
+ [subscriber sendNext:dictionary];
+ [subscriber sendCompleted];
+ }
+ else {
+ [subscriber sendError:parseError];
+ }
+ }
+ else {
+ [subscriber sendError:connectionError];
+ }
+ }];
+ return nil;
+ }];
+}
+
+
+- (NSDictionary *)dictionaryWithAccount:(NSDictionary *)account accessToken:(NSDictionary *)accessToken {
+ NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
+
+ // Provider
+ dictionary[@"provider"] = [[self class] type];
+
+ // Credentials
+ dictionary[@"credentials"] = @{@"token" : accessToken[@"access_token"]};
+
+ // User ID
+ dictionary[@"uid"] = account[@"id"];
+
+ // Raw response
+ dictionary[@"extra"] = @{
+ @"raw_info" : account
+ };
+
+ // User info
+ NSMutableDictionary *user = [NSMutableDictionary new];
+ user[@"name"] = account[@"name"];
+ user[@"username"] = account[@"username"];
+ user[@"image"] = account[@"avatar_url"];
+ dictionary[@"info"] = user;
+
+ return dictionary;
+}
+
+@end
diff --git a/SimpleAuth.podspec b/SimpleAuth.podspec
index 4a9df8f..e085143 100755
--- a/SimpleAuth.podspec
+++ b/SimpleAuth.podspec
@@ -128,4 +128,10 @@ Pod::Spec.new do |s|
ss.private_header_files = 'Pod/Providers/OneDriveWeb/*.h'
end
+ s.subspec 'Dribbble' do |ss|
+ ss.dependency 'SimpleAuth/Core'
+ ss.source_files = 'Pod/Providers/Dribbble'
+ ss.private_header_files = 'Pod/Providers/Dribbble/*.h'
+ end
+
end