Created
March 19, 2014 04:20
-
-
Save bobspryn/9635370 to your computer and use it in GitHub Desktop.
TwitterAuth.m
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| self.accountStore = [[ACAccountStore alloc] init]; | |
| self.pickTwitterAccountCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(ACAccount *account) { | |
| return [RACSignal return:account]; | |
| }]; | |
| // Returns an error we handle when they cancel picking from multiple twitter accounts | |
| RACSignal *cancelledPickingTwitterAccount = [[[self.pickTwitterAccountCommand.executionSignals switchToLatest] | |
| filter:^BOOL(ACAccount *account) { | |
| return account == nil; | |
| }] | |
| flattenMap:^RACStream *(id value) { | |
| return [RACSignal error:[NSError errorWithDomain:ThreeCentsErrorDomain code:ThreeCentsErrorCancelledTwitterLogin userInfo:nil]]; | |
| }]; | |
| // WHen they select a twitter account from the multiple accounts | |
| RACSignal *selectedTwitterAccount = [[self.pickTwitterAccountCommand.executionSignals switchToLatest] | |
| filter:^BOOL(ACAccount *account) { | |
| return account != nil; | |
| }]; | |
| // Returns all twitter accounts for this iPhone | |
| RACSignal *allTwitterAccounts = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { | |
| @strongify(self); | |
| ACAccountType *twitterType = [self.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter]; | |
| [_accountStore requestAccessToAccountsWithType:twitterType options:NULL completion:^(BOOL granted, NSError *error) { | |
| @strongify(self); | |
| if (granted) { | |
| NSArray *accounts = [self.accountStore accountsWithAccountType:twitterType]; | |
| if (accounts.count > 0) { | |
| [subscriber sendNext:accounts]; | |
| [subscriber sendCompleted]; | |
| } else { | |
| [subscriber sendError:[NSError errorWithDomain:ThreeCentsErrorDomain code:ThreeCentsErrorNoTwitterAccounts userInfo:nil]]; | |
| } | |
| } else { | |
| [subscriber sendError:[NSError errorWithDomain:ThreeCentsErrorDomain code:ThreeCentsErrorTwitterAccessDenied userInfo:nil]]; | |
| } | |
| }]; | |
| return nil; | |
| }]; | |
| // Just pairs the current twitter ID with the twitter accounts | |
| RACSignal *allAccountsWithTwitterID = [allTwitterAccounts zipWith:[RACSignal return:me.twitterUserID]]; | |
| // Found an account matching the existing twitter ID | |
| RACSignal *matchingTwitterAccountSignal = [[[allAccountsWithTwitterID | |
| filter:^BOOL(RACTuple *values) { | |
| NSNumber *twitterID = values.second; | |
| return twitterID != nil; | |
| }] | |
| flattenMap:^RACStream *(RACTuple *values) { | |
| RACTupleUnpack(NSArray *accounts, NSNumber *twitterID) = values; | |
| for (ACAccount *account in accounts) { | |
| NSString *userID = [account valueForKeyPath:@"properties.user_id"]; | |
| if ([userID isEqualToString:twitterID.stringValue]) { | |
| return [RACSignal return:account]; | |
| } | |
| } | |
| return [RACSignal error:[NSError errorWithDomain:ThreeCentsErrorDomain code:ThreeCentsErrorTwitterAccountMissing userInfo:nil]]; | |
| }] | |
| ignore:nil]; | |
| // No account previously selected | |
| RACSignal *noCurrentTwitterAcccount = [[allAccountsWithTwitterID | |
| filter:^BOOL(RACTuple *values) { | |
| NSNumber *twitterID = values.second; | |
| return twitterID == nil; | |
| }] | |
| reduceEach:^id (NSArray *accounts, NSNumber *twitterID){ | |
| return accounts; | |
| }]; | |
| // Authorizing for the first time and only found one account | |
| RACSignal *twitterAccountsReturnedOnlyOneSignal = [[noCurrentTwitterAcccount | |
| filter:^BOOL(NSArray *array) { | |
| return array.count == 1; | |
| }] | |
| map:^id(NSArray *accounts) { | |
| return accounts.firstObject; | |
| }]; | |
| // we arrive at an account one way or another | |
| RACSignal *accountSignal = [RACSignal merge:@[twitterAccountsReturnedOnlyOneSignal, | |
| selectedTwitterAccount, | |
| cancelledPickingTwitterAccount, | |
| matchingTwitterAccountSignal]]; | |
| self.authorizeTwitterCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { | |
| @strongify(self); | |
| // Assign multiple twitter accounts to this array which the VC will observe | |
| RAC(self, twitterAccountsToSelectFrom) = [[noCurrentTwitterAcccount | |
| filter:^BOOL(NSArray *twitterAccounts) { | |
| return twitterAccounts.count > 1; | |
| }] | |
| catchTo:[RACSignal return:nil]]; | |
| return [[[[[accountSignal | |
| take:1] | |
| flattenMap:^RACStream *(ACAccount *account) { | |
| return [[TCAPI fetchRequestToken] zipWith:[RACSignal return:account]]; | |
| }] | |
| flattenMap:^RACStream *(RACTuple *values) { | |
| RACTupleUnpack(NSString *reverseAuthSignature, ACAccount *account) = values; | |
| return [[TCAPI fetchTwitterOauthTokenWithAccount:account reverseAuthSignature:reverseAuthSignature] zipWith:[RACSignal return:account]]; | |
| }] | |
| // now we have the token, store with our server | |
| flattenMap:^RACStream *(RACTuple *values) { | |
| RACTupleUnpack(NSDictionary *twitterData, ACAccount *account) = values; | |
| return [[TCAPI addUpdateTwitterAccountToken:twitterData[kTCTwitterOAuthTokenKey] secret:twitterData[kTCTwitterOAuthTokenSecretKey]] | |
| mapReplace:account]; | |
| }] | |
| catch:^RACSignal *(NSError *error) { | |
| if ([error.domain isEqualToString:ThreeCentsErrorDomain]) { | |
| return [RACSignal error:error]; | |
| } | |
| return [RACSignal error:[NSError errorWithDomain:ThreeCentsErrorDomain code:ThreeCentsErrorTwitterLoginFailed userInfo:nil]]; | |
| }]; | |
| }]; |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Basically this identifies either a twitter account matching an existing user ID, finds a singular twitter account, or sets the
twitterAccountsToSelectFromproperty so the user can choose from multiple. The command subscribes to the result of any of those (or an error) and does some API work retrieving and updating a token before returning.