diff --git a/Classes/API/SEAPIRequestManager.h b/Classes/API/SEAPIRequestManager.h index 8489976..f7c3ff5 100644 --- a/Classes/API/SEAPIRequestManager.h +++ b/Classes/API/SEAPIRequestManager.h @@ -1,7 +1,7 @@ // // SEAPIRequestManager.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ #import -@class SEProvider, SELogin, SEError; +@class SEProvider, SELogin, SEError, SELoginAttempt; @protocol SELoginFetchingDelegate; @@ -47,6 +47,15 @@ typedef void (^SEAPIRequestFailureBlock)(SEError* error); */ + (void)linkClientId:(NSString*)clientId appSecret:(NSString*)appSecret; + +/** + Links your Customer Secret to the request manager. All outgoing requests related to logins will have the proper customer-related HTTP headers set by default. + + @param customerSecret The string identifying the customer. + @see https://docs.saltedge.com/reference/#customers-create + */ ++ (void)linkCustomerSecret:(NSString*)customerSecret; + /** Creates a new customer or returns an error if such customer exists. @@ -55,6 +64,7 @@ typedef void (^SEAPIRequestFailureBlock)(SEError* error); @param failure The callback block if the request fails. @warning identifier cannot be nil. + @see https://docs.saltedge.com/reference/#customers-create */ - (void)createCustomerWithIdentifier:(NSString*)identifier success:(void (^)(NSDictionary* responseObject))success @@ -73,7 +83,6 @@ typedef void (^SEAPIRequestFailureBlock)(SEError* error); @code // parameters example, listing only the required fields { - "customer_id": "AtQX6Q8vRyMrPjUVtW7J_O1n06qYQ25bvUJ8CIC80-8", "country_code": "XF", "provider_code": "fakebank_simple_xf", "credentials": { @@ -103,7 +112,6 @@ typedef void (^SEAPIRequestFailureBlock)(SEError* error); @code // parameters example, listing only the required fields { - "customer_id": "AtQX6Q8vRyMrPjUVtW7J_O1n06qYQ25bvUJ8CIC80-8", "country_code": "XO", "provider_code": "paypal_xo", "return_to": "your-app-url://home.local" @@ -282,6 +290,30 @@ typedef void (^SEAPIRequestFailureBlock)(SEError* error); success:(void (^)(SELogin* login))success failure:(SEAPIRequestFailureBlock)failure; +/** + Fetches a certain attempt for a login. + + @param attemptId The id of the attempt that is going to be fetched. + @param loginSecret The secret of the login whose attempt is going to be fetched. + @param success The callback block if the request succeeds. + @param failure The callback block if the request fails. + */ +- (void)fetchAttemptWithId:(NSNumber*)attemptId + forLoginWithSecret:(NSString*)loginSecret + success:(void (^)(SELoginAttempt*))success + failure:(SEAPIRequestFailureBlock)failure; + +/** + Fetches all attempts of a login. + + @param loginSecret The secret of the login whose attempts will be requested. + @param success The callback block if the request succeeds. + @param failure The callback block if the request fails. + */ +- (void)fetchAttemptsForLoginWithSecret:(NSString*)loginSecret + success:(void (^)(NSArray* attempts))success + failure:(SEAPIRequestFailureBlock)failure; + /** Provides an interactive login with a set of credentials. @@ -406,14 +438,13 @@ typedef void (^SEAPIRequestFailureBlock)(SEError* error); @param success The callback block if the request succeeds. @param failure The callback block if the request fails. - @warning parameters cannot be nil. Required fields are: "country_code", "provider_code", "customer_id", "return_to" + @warning parameters cannot be nil. Required fields are: "country_code", "provider_code", "return_to" @code // parameters example, listing only the required fields { "country_code": "XO" "provider_code": "paypal_xo", - "customer_id": "customer id string", "return_to": "http://example.com" } @endcode diff --git a/Classes/API/SEAPIRequestManager.m b/Classes/API/SEAPIRequestManager.m index c587cf8..9821b6d 100644 --- a/Classes/API/SEAPIRequestManager.m +++ b/Classes/API/SEAPIRequestManager.m @@ -1,7 +1,7 @@ // // SEAPIRequestManager.m // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -32,13 +32,15 @@ #import "SERequestHandler.h" #import "SEError.h" #import "SELoginFetchingDelegate.h" +#import "SELoginAttempt.h" /* HTTP Headers */ -static NSString* const kAppSecretHeaderKey = @"App-secret"; -static NSString* const kClientIdHeaderKey = @"Client-id"; -static NSString* const kLoginSecretHeaderKey = @"Login-secret"; -static NSString* const kContentTypeHeaderKey = @"Content-type"; -static NSString* const kJSONContentTypeValue = @"application/json"; +static NSString* const kAppSecretHeaderKey = @"App-secret"; +static NSString* const kClientIdHeaderKey = @"Client-id"; +static NSString* const kCustomerSecretHeaderKey = @"Customer-secret"; +static NSString* const kLoginSecretHeaderKey = @"Login-secret"; +static NSString* const kContentTypeHeaderKey = @"Content-type"; +static NSString* const kJSONContentTypeValue = @"application/json"; /* HTTP Session config */ static NSDictionary* sessionHeaders; @@ -46,6 +48,10 @@ /* Login polling */ static CGFloat const kLoginPollDelayTime = 5.0f; +/* Other */ +static NSString* const kJavascriptCallbackTypeKey = @"javascript_callback_type"; +static NSString* const kiFrameCallbackType = @"iframe"; + @interface SEAPIRequestManager(/* Private */) @property (nonatomic, strong) NSString* baseURL; @@ -76,7 +82,15 @@ + (void)linkClientId:(NSString *)clientId appSecret:(NSString *)appSecret NSAssert(clientId != nil, @"Client ID cannot be nil"); NSAssert(appSecret != nil, @"App secret cannot be nil"); - sessionHeaders = @{ kClientIdHeaderKey : clientId, kAppSecretHeaderKey : appSecret, kContentTypeHeaderKey : kJSONContentTypeValue }; + NSDictionary* appHeadersDictionary = @{ kClientIdHeaderKey : clientId, kAppSecretHeaderKey : appSecret, kContentTypeHeaderKey : kJSONContentTypeValue }; + sessionHeaders = [self sessionHeadersMergedWithDictionary:appHeadersDictionary]; +} + ++ (void)linkCustomerSecret:(NSString *)customerSecret +{ + NSAssert(customerSecret != nil, @"Customer Secret cannot be nil"); + + sessionHeaders = [self sessionHeadersMergedWithDictionary:@{ kCustomerSecretHeaderKey : customerSecret }]; } #pragma mark - Instance Methods @@ -107,9 +121,9 @@ - (void)createLoginWithParameters:(NSDictionary*)parameters failure:(SEAPIRequestFailureBlock)failure delegate:(id)delegate { + NSAssert(sessionHeaders[kCustomerSecretHeaderKey] != nil, @"Customer Secret cannot be nil."); NSAssert(parameters[kCountryCodeKey] != nil, @"Country code cannot be nil."); NSAssert(parameters[kProviderCodeKey] != nil, @"Provider code cannot be nil."); - NSAssert(parameters[kCustomerIdKey] != nil, @"Customer ID cannot be nil."); NSAssert(parameters[kCredentialsKey] != nil, @"Credentials cannot be nil."); [SERequestHandler sendPOSTRequestWithURL:[self baseURLStringByAppendingPathComponent:kLoginPath] @@ -137,9 +151,9 @@ - (void)createOAuthLoginWithParameters:(NSDictionary*)parameters failure:(SEAPIRequestFailureBlock)failure delegate:(id)delegate { + NSAssert(sessionHeaders[kCustomerSecretHeaderKey] != nil, @"Customer Secret cannot be nil."); NSAssert(parameters[kCountryCodeKey] != nil, @"Country code cannot be nil."); NSAssert(parameters[kProviderCodeKey] != nil, @"Provider code cannot be nil."); - NSAssert(parameters[kCustomerIdKey] != nil, @"Customer ID cannot be nil."); NSAssert(parameters[kReturnToKey] != nil, @"Return to URL cannot be nil."); NSString* OAuthCreatePath = [[self baseURLStringByAppendingPathComponent:kOAuthProvidersPath] stringByAppendingPathComponent:kLoginActionCreate]; @@ -228,6 +242,7 @@ - (void)fetchFullAccountsListForLoginSecret:(NSString*)loginSecret success:(void (^)(NSSet* accounts))success failure:(SEAPIRequestFailureBlock)failure { + NSAssert(sessionHeaders[kCustomerSecretHeaderKey] != nil, @"Customer Secret cannot be nil."); NSAssert(loginSecret != nil, @"Login secret cannot be nil."); [SERequestHandler sendGETRequestWithURL:[self baseURLStringByAppendingPathComponent:kAccountsPath] @@ -305,6 +320,7 @@ - (void)fetchLoginWithSecret:(NSString*)loginSecret success:(void (^)(SELogin* login))success failure:(SEAPIRequestFailureBlock)failure { + NSAssert(sessionHeaders[kCustomerSecretHeaderKey] != nil, @"Customer Secret cannot be nil."); NSAssert(loginSecret != nil, @"Login secret cannot be nil."); [SERequestHandler sendGETRequestWithURL:[self baseURLStringByAppendingPathComponent:kLoginPath] @@ -320,12 +336,53 @@ - (void)fetchLoginWithSecret:(NSString*)loginSecret }]; } +- (void)fetchAttemptWithId:(NSNumber *)attemptId + forLoginWithSecret:(NSString *)loginSecret + success:(void (^)(SELoginAttempt*))success + failure:(SEAPIRequestFailureBlock)failure +{ + NSAssert(sessionHeaders[kCustomerSecretHeaderKey] != nil, @"Customer Secret cannot be nil."); + NSAssert(attemptId != nil, @"Attempt id cannot be nil."); + NSAssert(loginSecret != nil, @"Login secret cannot be nil."); + + NSString* attemptPath = [[self baseURLStringByAppendingPathComponent:kAttemptsPath] stringByAppendingPathComponent:attemptId.description]; + [SERequestHandler sendGETRequestWithURL:attemptPath + parameters:nil + headers:[self sessionHeadersWithLoginSecret:loginSecret] + success:^(NSDictionary* responseObject) { + success([SELoginAttempt objectFromDictionary:responseObject[kDataKey]]); + } + failure:^(NSDictionary* error) { + [self failureBlockWithBlock:failure errorObject:error]; + }]; +} + +- (void)fetchAttemptsForLoginWithSecret:(NSString *)loginSecret + success:(void (^)(NSArray *))success + failure:(SEAPIRequestFailureBlock)failure +{ + [self requestPaginatedResourceWithPath:kAttemptsPath + container:@[].mutableCopy + headers:[self sessionHeadersWithLoginSecret:loginSecret] + parameters:nil + success:^(NSArray* attemptsArray) { + NSMutableArray* serializedAttempts = [NSMutableArray arrayWithCapacity:attemptsArray.count]; + for (NSDictionary* attemptDictionary in attemptsArray) { + [serializedAttempts addObject:[SELoginAttempt objectFromDictionary:attemptDictionary]]; + } + success([NSArray arrayWithArray:serializedAttempts]); + } + failure:failure + full:YES]; +} + - (void)provideInteractiveCredentialsForLoginWithSecret:(NSString*)loginSecret credentials:(NSDictionary*)credentials success:(void (^)(SELogin* login))success failure:(SEAPIRequestFailureBlock)failure delegate:(id)delegate { + NSAssert(sessionHeaders[kCustomerSecretHeaderKey] != nil, @"Customer Secret cannot be nil."); NSAssert(loginSecret != nil, @"Login secret cannot be nil."); NSAssert(credentials != nil, @"Credentials cannot be nil."); @@ -355,6 +412,7 @@ - (void)reconnectLoginWithSecret:(NSString*)loginSecret failure:(SEAPIRequestFailureBlock)failure delegate:(id)delegate { + NSAssert(sessionHeaders[kCustomerSecretHeaderKey] != nil, @"Customer Secret cannot be nil."); NSAssert(loginSecret != nil, @"Login secret cannot be nil."); NSAssert(credentials != nil, @"Credentials cannot be nil."); @@ -384,6 +442,7 @@ - (void)reconnectOAuthLoginWithSecret:(NSString*)loginSecret success:(void (^)(NSDictionary* responseObject))success failure:(SEAPIRequestFailureBlock)failure { + NSAssert(sessionHeaders[kCustomerSecretHeaderKey] != nil, @"Customer Secret cannot be nil."); NSAssert(loginSecret != nil, @"Login secret cannot be nil."); NSAssert(parameters[kReturnToKey] != nil, @"Return to URL cannot be nil."); @@ -407,6 +466,7 @@ - (void)refreshLoginWithSecret:(NSString*)loginSecret failure:(SEAPIRequestFailureBlock)failure delegate:(id)delegate { + NSAssert(sessionHeaders[kCustomerSecretHeaderKey] != nil, @"Customer Secret cannot be nil."); NSAssert(loginSecret != nil, @"Login secret cannot be nil."); NSString* refreshPath = [[self baseURLStringByAppendingPathComponent:kLoginPath] stringByAppendingPathComponent:kLoginActionRefresh]; @@ -434,6 +494,7 @@ - (void)refreshOAuthLoginWithSecret:(NSString*)loginSecret success:(void (^)(NSDictionary* responseObject))success failure:(SEAPIRequestFailureBlock)failure { + NSAssert(sessionHeaders[kCustomerSecretHeaderKey] != nil, @"Customer Secret cannot be nil."); NSAssert(loginSecret != nil, @"Login secret cannot be nil."); NSAssert(parameters[kReturnToKey] != nil, @"Return to URL cannot be nil."); @@ -456,6 +517,7 @@ - (void)removeLoginWithSecret:(NSString*)loginSecret success:(void (^)(NSDictionary* responseObject))success failure:(SEAPIRequestFailureBlock)failure { + NSAssert(sessionHeaders[kCustomerSecretHeaderKey] != nil, @"Customer Secret cannot be nil."); NSAssert(loginSecret != nil, @"Login secret cannot be nil."); [SERequestHandler sendDELETERequestWithURL:[self baseURLStringByAppendingPathComponent:kLoginPath] @@ -475,16 +537,14 @@ - (void)requestCreateTokenWithParameters:(NSDictionary*)parameters success:(void (^)(NSDictionary* responseObject))success failure:(SEAPIRequestFailureBlock)failure { + NSAssert(sessionHeaders[kCustomerSecretHeaderKey] != nil, @"Customer Secret cannot be nil."); NSAssert(parameters[kCountryCodeKey] != nil, @"Country code cannot be nil."); NSAssert(parameters[kProviderCodeKey] != nil, @"Provider code cannot be nil."); NSAssert(parameters[kReturnToKey] != nil, @"Return to cannot be nil."); - NSAssert(parameters[kCustomerIdKey] != nil, @"Customer ID cannot be nil."); - - NSDictionary* dataParameters = @{ kDataKey: parameters }; [self requestTokenWithAction:kLoginActionCreate headers:sessionHeaders - parameters:dataParameters + parameters:parameters success:success failure:failure]; } @@ -494,6 +554,7 @@ - (void)requestReconnectTokenForLoginSecret:(NSString*)loginSecret success:(void (^)(NSDictionary* responseObject))success failure:(SEAPIRequestFailureBlock)failure { + NSAssert(sessionHeaders[kCustomerSecretHeaderKey] != nil, @"Customer Secret cannot be nil."); NSAssert(loginSecret != nil, @"Login secret cannot be nil."); NSAssert(parameters[kReturnToKey] != nil, @"Return to cannot be nil."); @@ -509,6 +570,7 @@ - (void)requestRefreshTokenForLoginSecret:(NSString*)loginSecret success:(void (^)(NSDictionary* responseObject))success failure:(SEAPIRequestFailureBlock)failure { + NSAssert(sessionHeaders[kCustomerSecretHeaderKey] != nil, @"Customer Secret cannot be nil."); NSAssert(loginSecret != nil, @"Login secret cannot be nil."); NSAssert(parameters[kReturnToKey] != nil, @"Return to cannot be nil."); @@ -536,10 +598,15 @@ - (void)requestTokenWithAction:(NSString*)path success:(void (^)(NSDictionary* responseObject))success failure:(SEAPIRequestFailureBlock)failure { + + NSMutableDictionary* mutableParams = parameters.mutableCopy; + mutableParams[kJavascriptCallbackTypeKey] = kiFrameCallbackType; + NSDictionary* dataParameters = @{ kDataKey: mutableParams }; + NSString* tokenPath = [[self baseURLStringByAppendingPathComponent:kTokensPath] stringByAppendingPathComponent:path]; [SERequestHandler sendPOSTRequestWithURL:tokenPath - parameters:parameters + parameters:dataParameters headers:headers success:^(NSDictionary* responseObject) { if (success) { @@ -584,6 +651,7 @@ - (void)requestTransactionsListWithPath:(NSString*)transactionsPath success:(void (^)(NSSet* transactions))success failure:(SEAPIRequestFailureBlock)failure { + NSAssert(sessionHeaders[kCustomerSecretHeaderKey] != nil, @"Customer Secret cannot be nil."); NSAssert(accountId != nil, @"Account id cannot be nil."); NSAssert(loginSecret != nil, @"Login secret cannot be nil."); @@ -626,10 +694,10 @@ - (void)pollLoginWithSecret:(NSString*)loginSecret [self fetchLoginWithSecret:loginSecret success:^(SELogin* fetchedLogin) { - if ([fetchedLogin.stage isEqualToString:kLoginStageInteractive]) { + if ([[fetchedLogin stage] isEqualToString:kLoginStageInteractive]) { [self.loginFetchingDelegate loginRequestedInteractiveInput:fetchedLogin]; - } else if ([fetchedLogin.stage isEqualToString:kLoginStageFinish]) { - if (!fetchedLogin.lastFailMessage || [fetchedLogin.lastFailMessage isEqualToString:@""]) { + } else if ([[fetchedLogin stage] isEqualToString:kLoginStageFinish]) { + if (![fetchedLogin lastFailMessage] || [[fetchedLogin lastFailMessage] isEqualToString:@""]) { [self.loginFetchingDelegate loginSuccessfullyFinishedFetching:fetchedLogin]; } else { [self.loginFetchingDelegate login:fetchedLogin failedToFetchWithMessage:fetchedLogin.lastFailMessage]; @@ -639,7 +707,7 @@ - (void)pollLoginWithSecret:(NSString*)loginSecret } } failure:^(SEError* failure) { - [self.loginFetchingDelegate login:self.createdLogin failedToFetchWithMessage:failure.message]; + [self.loginFetchingDelegate login:self.createdLogin failedToFetchWithMessage:failure.errorMessage]; self.createdLogin = nil; }]; } @@ -649,6 +717,7 @@ - (void)learnTransactionCategoriesForLoginSecret:(NSString*)loginSecret success:(void (^)(NSDictionary* responseObject))success failure:(SEAPIRequestFailureBlock)failure { + NSAssert(sessionHeaders[kCustomerSecretHeaderKey] != nil, @"Customer Secret cannot be nil."); NSAssert(learningArray != nil, @"learningArray cannot be nil."); [SERequestHandler sendPOSTRequestWithURL:[self baseURLStringByAppendingPathComponent:kLearnPath] @@ -690,8 +759,17 @@ - (void)failureBlockWithBlock:(SEAPIRequestFailureBlock)failureBlock errorObject + (NSDictionary*)sessionHeadersWithLoginSecret:(NSString*)loginSecret { + return [self sessionHeadersMergedWithDictionary:@{ kLoginSecretHeaderKey : loginSecret }]; +} + ++ (NSDictionary*)sessionHeadersMergedWithDictionary:(NSDictionary*)dictionary +{ + if (!sessionHeaders) { + sessionHeaders = [NSDictionary dictionary]; + } + NSMutableDictionary* mutableSessionHeaders = sessionHeaders.mutableCopy; - mutableSessionHeaders[kLoginSecretHeaderKey] = loginSecret; + [mutableSessionHeaders addEntriesFromDictionary:dictionary]; return [NSDictionary dictionaryWithDictionary:mutableSessionHeaders]; } diff --git a/Classes/API/SEAPIRequestManager_private.h b/Classes/API/SEAPIRequestManager_private.h index 2437133..922d729 100644 --- a/Classes/API/SEAPIRequestManager_private.h +++ b/Classes/API/SEAPIRequestManager_private.h @@ -3,7 +3,7 @@ // Salt Edge API Demo // // Created by nemesis on 10/29/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // @interface SEAPIRequestManager() diff --git a/Classes/API/SELoginFetchingDelegate.h b/Classes/API/SELoginFetchingDelegate.h index 3abed4e..98cd6eb 100755 --- a/Classes/API/SELoginFetchingDelegate.h +++ b/Classes/API/SELoginFetchingDelegate.h @@ -1,7 +1,7 @@ // // SELoginFetchingDelegate.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/API/SERequestHandler.h b/Classes/API/SERequestHandler.h index 2693242..72da55c 100644 --- a/Classes/API/SERequestHandler.h +++ b/Classes/API/SERequestHandler.h @@ -1,7 +1,7 @@ // // SERequestHandler.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/API/SERequestHandler.m b/Classes/API/SERequestHandler.m index cfa0200..28e979d 100644 --- a/Classes/API/SERequestHandler.m +++ b/Classes/API/SERequestHandler.m @@ -1,7 +1,7 @@ // // SERequestHandler.m // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -47,12 +47,12 @@ typedef NS_ENUM(NSInteger, SERequestMethod) { SERequestMethodPUT }; -@interface SERequestHandler (/* Private */) +static NSURLSession* _requestHandlerURLSession; -@property (nonatomic, strong) NSMutableData* responseData; -@property (nonatomic, copy) SERequestHandlerFailureBlock successBlock; -@property (nonatomic, copy) SERequestHandlerFailureBlock failureBlock; -@property (nonatomic) NSInteger responseStatusCode; +@interface SERequestHandler (/* Private */) + +@property (nonatomic, copy) SERequestHandlerFailureBlock successBlock; +@property (nonatomic, copy) SERequestHandlerFailureBlock failureBlock; @end @@ -61,6 +61,16 @@ @implementation SERequestHandler #pragma mark - #pragma mark - Public API ++ (void)initialize +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSURLSessionConfiguration* sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; + sessionConfig.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData; + _requestHandlerURLSession = [NSURLSession sessionWithConfiguration:sessionConfig]; + }); +} + + (void)sendDELETERequestWithURL:(NSString*)url parameters:(NSDictionary*)parameters headers:(NSDictionary*)headers @@ -148,7 +158,34 @@ - (void)sendRequest:(SERequestMethod)method } } - [NSURLConnection connectionWithRequest:request delegate:self]; + NSURLSessionDataTask* task = [_requestHandlerURLSession dataTaskWithRequest:request completionHandler:^(NSData* responseData, NSURLResponse* response, NSError* responseError) { + dispatch_async(dispatch_get_main_queue(), ^{ + if (responseError) { + self.failureBlock(@{ kErrorClassKey : responseError.domain, + kMessageKey : responseError.localizedDescription, + kRequestKey : request + }); + return; + } + + NSInteger responseStatusCode = [(NSHTTPURLResponse*)response statusCode]; + NSError* error; + NSDictionary* data = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&error]; + if (error) { + self.failureBlock(@{ kErrorClassKey : error.domain, + kMessageKey : error.localizedDescription, + kRequestKey : request }); + } else { + if ((responseStatusCode >= 200 && responseStatusCode < 300)) { + self.successBlock(data); + } else { + self.failureBlock(data); + } + } + }); + }]; + + [task resume]; } - (NSString*)stringForMethod:(SERequestMethod)method @@ -204,52 +241,4 @@ - (NSArray*)HTTPMethodsWithoutBody return @[kRequestMethodGET, kRequestMethodDELETE]; } -- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace -{ - return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]; -} - -- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response -{ - self.responseData = [[NSMutableData alloc] init]; - self.responseStatusCode = [(NSHTTPURLResponse*)response statusCode]; -} - -- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data -{ - [self.responseData appendData:data]; -} - -- (void)connectionDidFinishLoading:(NSURLConnection*)connection -{ - NSError* error; - NSDictionary* data = [NSJSONSerialization JSONObjectWithData:self.responseData options:0 error:&error]; - if (error) { - self.failureBlock(@{ kErrorClassKey : error.domain, - kMessageKey : error.localizedDescription, - kRequestKey : connection.currentRequest }); - } else { - if ((self.responseStatusCode >= 200 && self.responseStatusCode < 300)) { - self.successBlock(data); - } else { - self.failureBlock(data); - } - } -} - -- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error -{ - if (self.failureBlock) { - self.failureBlock(@{ kErrorClassKey : error.domain, - kMessageKey : error.localizedDescription, - kRequestKey : connection.currentRequest - }); - } -} - -- (NSCachedURLResponse*)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse -{ - return nil; -} - @end diff --git a/Classes/Categories/NSString+SEModelsSerializingAdditions.h b/Classes/Categories/NSString+SEModelsSerializingAdditions.h index cad1c7f..24ca8de 100644 --- a/Classes/Categories/NSString+SEModelsSerializingAdditions.h +++ b/Classes/Categories/NSString+SEModelsSerializingAdditions.h @@ -1,7 +1,7 @@ // // NSString+SEModelsSerializingAdditions.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/Categories/NSString+SEModelsSerializingAdditions.m b/Classes/Categories/NSString+SEModelsSerializingAdditions.m index f875754..5c5b902 100644 --- a/Classes/Categories/NSString+SEModelsSerializingAdditions.m +++ b/Classes/Categories/NSString+SEModelsSerializingAdditions.m @@ -1,7 +1,7 @@ // // NSString+SEModelsSerializingAdditions.m // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/Categories/NSURL+SEQueryArgmuentsAdditions.h b/Classes/Categories/NSURL+SEQueryArgmuentsAdditions.h index 8a162a2..786307e 100644 --- a/Classes/Categories/NSURL+SEQueryArgmuentsAdditions.h +++ b/Classes/Categories/NSURL+SEQueryArgmuentsAdditions.h @@ -1,7 +1,7 @@ // // NSURL+SEQueryArgmuentsAdditions.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/Categories/NSURL+SEQueryArgmuentsAdditions.m b/Classes/Categories/NSURL+SEQueryArgmuentsAdditions.m index 7c3fac1..2d24cf3 100644 --- a/Classes/Categories/NSURL+SEQueryArgmuentsAdditions.m +++ b/Classes/Categories/NSURL+SEQueryArgmuentsAdditions.m @@ -1,7 +1,7 @@ // // NSURL+SEQueryArgmuentsAdditions.m // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/Categories/SEAPIRequestManager+SEOAuthLoginHandlingAdditions.h b/Classes/Categories/SEAPIRequestManager+SEOAuthLoginHandlingAdditions.h index deaf045..19d5916 100644 --- a/Classes/Categories/SEAPIRequestManager+SEOAuthLoginHandlingAdditions.h +++ b/Classes/Categories/SEAPIRequestManager+SEOAuthLoginHandlingAdditions.h @@ -1,7 +1,7 @@ // // SEAPIRequestManager+SEOAuthLoginHandlingAdditions.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/Categories/SEAPIRequestManager+SEOAuthLoginHandlingAdditions.m b/Classes/Categories/SEAPIRequestManager+SEOAuthLoginHandlingAdditions.m index ba733d9..101cf70 100644 --- a/Classes/Categories/SEAPIRequestManager+SEOAuthLoginHandlingAdditions.m +++ b/Classes/Categories/SEAPIRequestManager+SEOAuthLoginHandlingAdditions.m @@ -1,7 +1,7 @@ // // SEAPIRequestManager+SEOAuthLoginHandlingAdditions.m // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/Models/SEAccount.h b/Classes/Models/SEAccount.h index 58ca63f..d1e4ecc 100644 --- a/Classes/Models/SEAccount.h +++ b/Classes/Models/SEAccount.h @@ -1,7 +1,7 @@ // // SEAccount.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/Models/SEAccount.m b/Classes/Models/SEAccount.m index 63cf77e..543d941 100644 --- a/Classes/Models/SEAccount.m +++ b/Classes/Models/SEAccount.m @@ -1,7 +1,7 @@ // // SEAccount.m // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/Models/SEBaseModel.h b/Classes/Models/SEBaseModel.h index 0cd6c3e..11faf2c 100644 --- a/Classes/Models/SEBaseModel.h +++ b/Classes/Models/SEBaseModel.h @@ -1,7 +1,7 @@ // // SEBaseModel.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/Models/SEBaseModel.m b/Classes/Models/SEBaseModel.m index 03075c9..ac3a53a 100644 --- a/Classes/Models/SEBaseModel.m +++ b/Classes/Models/SEBaseModel.m @@ -1,7 +1,7 @@ // // SEBaseModel.m // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -31,7 +31,7 @@ @implementation SEBaseModel + (void)initialize { - dateTimePropertiesNames = @[@"createdAt", @"updatedAt", @"deletedAt", @"lastFailAt", @"lastSuccessAt", @"lastRequestAt"]; + dateTimePropertiesNames = @[@"createdAt", @"updatedAt", @"deletedAt", @"lastFailAt", @"lastSuccessAt", @"lastRequestAt", @"nextRefreshPossibleAt", @"successAt", @"failAt"]; datePropertyNames = @[@"madeOn"]; } diff --git a/Classes/Models/SEError.h b/Classes/Models/SEError.h index 574548a..2270972 100644 --- a/Classes/Models/SEError.h +++ b/Classes/Models/SEError.h @@ -1,7 +1,7 @@ // // SEError.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -31,7 +31,7 @@ @interface SEError : SEBaseModel @property (nonatomic, strong) NSString* errorClass; -@property (nonatomic, strong) NSString* message; +@property (nonatomic, strong) NSString* errorMessage; @property (nonatomic, strong) NSDictionary* request; @end diff --git a/Classes/Models/SEError.m b/Classes/Models/SEError.m index 5f38855..21d0321 100644 --- a/Classes/Models/SEError.m +++ b/Classes/Models/SEError.m @@ -1,7 +1,7 @@ // // SEError.m // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -27,7 +27,7 @@ @implementation SEError - (NSString*)description { - return [NSString stringWithFormat:@"*** ERROR: %@ -> %@. REQUEST: %@", self.errorClass, self.message, self.request]; + return [NSString stringWithFormat:@"*** ERROR: %@ -> %@. REQUEST: %@", self.errorClass, self.errorMessage, self.request]; } @end diff --git a/Classes/Models/SELogin.h b/Classes/Models/SELogin.h index 9561582..74ba877 100644 --- a/Classes/Models/SELogin.h +++ b/Classes/Models/SELogin.h @@ -1,7 +1,7 @@ // // SELogin.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -22,6 +22,7 @@ // THE SOFTWARE. #import "SEBaseModel.h" +#import "SELoginAttempt.h" /** SELogin represents a login within the Salt Edge system. @@ -30,27 +31,17 @@ */ @interface SELogin : SEBaseModel -@property (nonatomic, strong) NSNumber* id; -@property (nonatomic, strong) NSString* secret; -@property (nonatomic, strong) NSNumber* finished; -@property (nonatomic, strong) NSNumber* finishedRecent; -@property (nonatomic, strong) NSNumber* partial; -@property (nonatomic, strong) NSString* providerCode; -@property (nonatomic, strong) NSString* providerName; -@property (nonatomic, strong) NSNumber* automaticFetch; -@property (nonatomic, strong) NSNumber* interactive; -@property (nonatomic, strong) NSString* interactiveHtml; -@property (nonatomic, strong) NSArray* interactiveFieldsNames; -@property (nonatomic, strong) NSString* customerEmail; -@property (nonatomic, strong) NSDate* createdAt; -@property (nonatomic, strong) NSDate* updatedAt; -@property (nonatomic, strong) NSDate* lastFailAt; -@property (nonatomic, strong) NSString* lastFailMessage; -@property (nonatomic, strong) NSDate* lastRequestAt; -@property (nonatomic, strong) NSDate* lastSuccessAt; -@property (nonatomic, strong) NSString* status; -@property (nonatomic, strong) NSString* stage; -@property (nonatomic, strong) NSString* countryCode; +@property (nonatomic, strong) NSNumber* id; +@property (nonatomic, strong) SELoginAttempt* lastAttempt; +@property (nonatomic, strong) NSString* secret; +@property (nonatomic, strong) NSString* status; +@property (nonatomic, strong) NSString* countryCode; +@property (nonatomic, strong) NSString* providerCode; +@property (nonatomic, strong) NSString* providerName; +@property (nonatomic, strong) NSDate* createdAt; +@property (nonatomic, strong) NSDate* updatedAt; +@property (nonatomic, strong) NSDate* lastSuccessAt; +@property (nonatomic, strong) NSDate* nextRefreshPossibleAt; /** Tests whether the caller and the parameter are equal. @@ -59,4 +50,20 @@ */ - (BOOL)isEqualToLogin:(SELogin*)login; +/** + Convenience method for getting the last login stage from the last attempt. + This will be equal to the caller's lastAttempt.lastStage.name + + @return The login stage from the last attempt. + */ +- (NSString*)stage; + +/** + Convenience method for getting the last fail message from the last attempt. + This will be equal to the caller's lastAttempt.failMessage + + @return The login stage from the last attempt. + */ +- (NSString*)lastFailMessage; + @end diff --git a/Classes/Models/SELogin.m b/Classes/Models/SELogin.m index 8b1563e..3c32826 100644 --- a/Classes/Models/SELogin.m +++ b/Classes/Models/SELogin.m @@ -1,7 +1,7 @@ // // SELogin.m // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -23,8 +23,27 @@ #import "SELogin.h" +static NSString* const kLoginLastAttemptKey = @"last_attempt"; + @implementation SELogin ++ (instancetype)objectFromDictionary:(NSDictionary *)dictionary +{ + SELogin* object = [super objectFromDictionary:dictionary]; + object.lastAttempt = [SELoginAttempt objectFromDictionary:dictionary[kLoginLastAttemptKey]]; + return object; +} + +- (NSString*)stage +{ + return self.lastAttempt.lastStage.name; +} + +- (NSString*)lastFailMessage +{ + return self.lastAttempt.failMessage; +} + - (BOOL)isEqualToLogin:(SELogin*)login { return ([self.id integerValue] == [login.id integerValue]); diff --git a/Classes/Models/SELoginAttempt.h b/Classes/Models/SELoginAttempt.h new file mode 100644 index 0000000..24d05ea --- /dev/null +++ b/Classes/Models/SELoginAttempt.h @@ -0,0 +1,50 @@ +// +// SELoginAttempt.h +// +// Copyright (c) 2016 Salt Edge. https://saltedge.com +// +// 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 "SEBaseModel.h" +#import "SELoginAttemptStage.h" + +/** + SELoginAttempt represents an attempt to fetch a login. + + @warning When fetching a login attempt or getting it from a login object via login.lastAttempt, it may not have all fields present. + */ + +@interface SELoginAttempt : SEBaseModel + +@property (nonatomic, strong) NSNumber* id; +@property (nonatomic, strong) SELoginAttemptStage* lastStage; +@property (nonatomic, strong) NSArray* stages; +@property (nonatomic, strong) NSNumber* finished; +@property (nonatomic, strong) NSNumber* finishedRecent; +@property (nonatomic, strong) NSNumber* interactive; +@property (nonatomic, strong) NSNumber* partial; +@property (nonatomic, strong) NSNumber* automaticFetch; +@property (nonatomic, strong) NSDate* createdAt; +@property (nonatomic, strong) NSDate* updatedAt; +@property (nonatomic, strong) NSDate* successAt; +@property (nonatomic, strong) NSDate* failAt; +@property (nonatomic, strong) NSString* failErrorClass; +@property (nonatomic, strong) NSString* failMessage; + +@end diff --git a/Classes/Models/SELoginAttempt.m b/Classes/Models/SELoginAttempt.m new file mode 100644 index 0000000..495d31b --- /dev/null +++ b/Classes/Models/SELoginAttempt.m @@ -0,0 +1,48 @@ +// +// SELoginAttempt.m +// +// Copyright (c) 2016 Salt Edge. https://saltedge.com +// +// 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 "SELoginAttempt.h" +#import "SELoginAttemptStage.h" + +static NSString* const kLoginAttemptLastStageKey = @"last_stage"; +static NSString* const kLoginAttemptStagesKey = @"stages"; + +@implementation SELoginAttempt + ++ (instancetype)objectFromDictionary:(NSDictionary *)dictionary +{ + SELoginAttempt* object = [super objectFromDictionary:dictionary]; + if (dictionary[kLoginAttemptLastStageKey]) { + object.lastStage = [SELoginAttemptStage objectFromDictionary:dictionary[kLoginAttemptLastStageKey]]; + } + if (dictionary[kLoginAttemptStagesKey]) { + NSMutableArray* stagesObjects = [NSMutableArray arrayWithCapacity:[dictionary[kLoginAttemptStagesKey] count]]; + for (NSDictionary* stageDictionary in dictionary[kLoginAttemptStagesKey]) { + [stagesObjects addObject:[SELoginAttemptStage objectFromDictionary:stageDictionary]]; + } + object.stages = [NSArray arrayWithArray:stagesObjects]; + } + return object; +} + +@end diff --git a/Classes/Models/SELoginAttemptStage.h b/Classes/Models/SELoginAttemptStage.h new file mode 100644 index 0000000..c33f3d6 --- /dev/null +++ b/Classes/Models/SELoginAttemptStage.h @@ -0,0 +1,38 @@ +// +// SELoginAttemptStage.h +// +// Copyright (c) 2016 Salt Edge. https://saltedge.com +// +// 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 "SEBaseModel.h" + +/** + SELoginAttemptStage represents a stage within an attempt of a login fetch process. + */ + +@interface SELoginAttemptStage : SEBaseModel + +@property (nonatomic, strong) NSString* name; +@property (nonatomic, strong) NSString* interactiveHtml; +@property (nonatomic, strong) NSArray* interactiveFieldsNames; +@property (nonatomic, strong) NSDate* createdAt; +@property (nonatomic, strong) NSDate* updatedAt; + +@end diff --git a/Classes/Models/SELoginAttemptStage.m b/Classes/Models/SELoginAttemptStage.m new file mode 100644 index 0000000..23b9dc6 --- /dev/null +++ b/Classes/Models/SELoginAttemptStage.m @@ -0,0 +1,28 @@ +// +// SELoginAttemptStage.m +// +// Copyright (c) 2016 Salt Edge. https://saltedge.com +// +// 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 "SELoginAttemptStage.h" + +@implementation SELoginAttemptStage + +@end diff --git a/Classes/Models/SEProvider.h b/Classes/Models/SEProvider.h index 173038a..3eadf88 100644 --- a/Classes/Models/SEProvider.h +++ b/Classes/Models/SEProvider.h @@ -1,7 +1,7 @@ // // SEProvider.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/Models/SEProvider.m b/Classes/Models/SEProvider.m index 813d508..20d0401 100644 --- a/Classes/Models/SEProvider.m +++ b/Classes/Models/SEProvider.m @@ -1,7 +1,7 @@ // // SEProvider.m // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/Models/SEProviderField.h b/Classes/Models/SEProviderField.h index c2a26a8..172cbe8 100644 --- a/Classes/Models/SEProviderField.h +++ b/Classes/Models/SEProviderField.h @@ -1,7 +1,7 @@ // // SEProviderField.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/Models/SEProviderField.m b/Classes/Models/SEProviderField.m index d54543b..4bd3caa 100644 --- a/Classes/Models/SEProviderField.m +++ b/Classes/Models/SEProviderField.m @@ -1,7 +1,7 @@ // // SEProviderField.m // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/Models/SEProviderFieldOption.h b/Classes/Models/SEProviderFieldOption.h index b0815d3..5cf4e48 100644 --- a/Classes/Models/SEProviderFieldOption.h +++ b/Classes/Models/SEProviderFieldOption.h @@ -1,7 +1,7 @@ // // SEProviderFieldOption.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/Models/SEProviderFieldOption.m b/Classes/Models/SEProviderFieldOption.m index 8b2f3e1..887fde8 100644 --- a/Classes/Models/SEProviderFieldOption.m +++ b/Classes/Models/SEProviderFieldOption.m @@ -1,7 +1,7 @@ // // SEProviderFieldOption.m // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/Models/SETransaction.h b/Classes/Models/SETransaction.h index 6d76c3e..97e6c6f 100644 --- a/Classes/Models/SETransaction.h +++ b/Classes/Models/SETransaction.h @@ -1,7 +1,7 @@ // // SETransaction.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/Models/SETransaction.m b/Classes/Models/SETransaction.m index e591d57..9ced4c9 100644 --- a/Classes/Models/SETransaction.m +++ b/Classes/Models/SETransaction.m @@ -1,7 +1,7 @@ // // SETransaction.m // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/SEWebView/NSURL+SBCallbacksAdditions/NSURL+SECallbacksAdditions.h b/Classes/SEWebView/NSURL+SBCallbacksAdditions/NSURL+SECallbacksAdditions.h index 2785cb2..21ab431 100644 --- a/Classes/SEWebView/NSURL+SBCallbacksAdditions/NSURL+SECallbacksAdditions.h +++ b/Classes/SEWebView/NSURL+SBCallbacksAdditions/NSURL+SECallbacksAdditions.h @@ -1,7 +1,7 @@ // // NSURL+SECallbacksAdditions.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/SEWebView/NSURL+SBCallbacksAdditions/NSURL+SECallbacksAdditions.m b/Classes/SEWebView/NSURL+SBCallbacksAdditions/NSURL+SECallbacksAdditions.m index 04a0b1a..df7ac28 100644 --- a/Classes/SEWebView/NSURL+SBCallbacksAdditions/NSURL+SECallbacksAdditions.m +++ b/Classes/SEWebView/NSURL+SBCallbacksAdditions/NSURL+SECallbacksAdditions.m @@ -1,7 +1,7 @@ // // NSURL+SECallbacksAdditions.m // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/SEWebView/SEWebView.h b/Classes/SEWebView/SEWebView.h index a75bb03..f4161ff 100644 --- a/Classes/SEWebView/SEWebView.h +++ b/Classes/SEWebView/SEWebView.h @@ -1,7 +1,7 @@ // // SEWebView.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -27,7 +27,7 @@ static NSString* const SELoginStateError = @"error"; static NSString* const SELoginStateFetching = @"fetching"; static NSString* const SELoginStateSuccess = @"success"; -static NSString* const SELoginStateKey = @"state"; +static NSString* const SELoginStageKey = @"stage"; static NSString* const SELoginSecretKey = @"secret"; static NSString* const SELoginIDKey = @"login_id"; static NSString* const SELoginDuplicatedIDKey = @"duplicated_login_id"; diff --git a/Classes/SEWebView/SEWebView.m b/Classes/SEWebView/SEWebView.m index e35c7b7..fce5692 100644 --- a/Classes/SEWebView/SEWebView.m +++ b/Classes/SEWebView/SEWebView.m @@ -1,7 +1,7 @@ // // SEWebView.m // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -63,7 +63,7 @@ - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *) if ((callbackParameters[SELoginDataKey][SELoginSecretKey] || callbackParameters[SELoginDataKey][SELoginIDKey] || callbackParameters[SELoginDataKey][SELoginDuplicatedIDKey]) - && callbackParameters[SELoginDataKey][SELoginStateKey]) { + && callbackParameters[SELoginDataKey][SELoginStageKey]) { if ([self.stateDelegate respondsToSelector:@selector(webView:receivedCallbackWithResponse:)]) { [self.stateDelegate webView:self receivedCallbackWithResponse:callbackParameters]; } diff --git a/Classes/SEWebView/SEWebViewDelegate.h b/Classes/SEWebView/SEWebViewDelegate.h index e8a2427..4a44f85 100644 --- a/Classes/SEWebView/SEWebViewDelegate.h +++ b/Classes/SEWebView/SEWebViewDelegate.h @@ -1,7 +1,7 @@ // // SEWebViewDelegate.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/Utils/Constants.h b/Classes/Utils/Constants.h index dade8bf..44d5478 100644 --- a/Classes/Utils/Constants.h +++ b/Classes/Utils/Constants.h @@ -1,7 +1,7 @@ // // Constants.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,14 +26,15 @@ /* Routes and paths */ static NSString* const kRootURL = @"https://www.saltedge.com"; -static NSString* const kTokensPath = @"api/v2/tokens"; -static NSString* const kLoginPath = @"api/v2/login"; -static NSString* const kAccountsPath = @"api/v2/accounts"; -static NSString* const kTransactionsPath = @"api/v2/transactions"; -static NSString* const kProvidersPath = @"api/v2/providers"; -static NSString* const kOAuthProvidersPath = @"api/v2/oauth_providers"; -static NSString* const kCustomersPath = @"api/v2/customers"; -static NSString* const kLearnPath = @"api/v2/categories/learn"; +static NSString* const kTokensPath = @"api/v3/tokens"; +static NSString* const kLoginPath = @"api/v3/login"; +static NSString* const kAttemptsPath = @"api/v3/attempts"; +static NSString* const kAccountsPath = @"api/v3/accounts"; +static NSString* const kTransactionsPath = @"api/v3/transactions"; +static NSString* const kProvidersPath = @"api/v3/providers"; +static NSString* const kOAuthProvidersPath = @"api/v3/oauth_providers"; +static NSString* const kCustomersPath = @"api/v3/customers"; +static NSString* const kLearnPath = @"api/v3/categories/learn"; static NSString* const kLoginInteractive = @"interactive"; static NSString* const kPendingTransactions = @"pending"; @@ -63,7 +64,7 @@ static NSString* const kCountryCodeKey = @"country_code"; static NSString* const kProviderCodeKey = @"provider_code"; static NSString* const kReturnToKey = @"return_to"; static NSString* const kRedirectURLKey = @"redirect_url"; -static NSString* const kCustomerIdKey = @"customer_id"; +static NSString* const kCustomerSecretKey = @"secret"; static NSString* const kAccountIdKey = @"account_id"; static NSString* const kFromMadeOnKey = @"from_made_on"; static NSString* const kToMadeOnKey = @"to_made_on"; diff --git a/Classes/Utils/DateUtils.h b/Classes/Utils/DateUtils.h index eea6bd9..7e2dfd3 100644 --- a/Classes/Utils/DateUtils.h +++ b/Classes/Utils/DateUtils.h @@ -1,7 +1,7 @@ // // DateUtils.h // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/Classes/Utils/DateUtils.m b/Classes/Utils/DateUtils.m index 0c90bd4..4bd2081 100644 --- a/Classes/Utils/DateUtils.m +++ b/Classes/Utils/DateUtils.m @@ -1,7 +1,7 @@ // // DateUtils.m // -// Copyright (c) 2015 Salt Edge. https://saltedge.com +// Copyright (c) 2016 Salt Edge. https://saltedge.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 236d213..99b9498 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A handful of classes to help you interact with the Salt Edge API from your iOS a ## Requirements -iOS 6+, ARC. +iOS 7+, ARC. ## Installation ### CocoaPods @@ -263,7 +263,7 @@ Set up the `clientId`, `appSecret` and `customerIdentifier` constants to your Cl ## Versioning -The current version of the SDK is [2.6.0](https://github.com/saltedge/saltedge-ios/releases/tag/v2.6.0), and is in compliance with the Salt Edge API's [current version](https://docs.saltedge.com/#version_management). Any backward-incompatible changes in the API will result in changes to the SDK. +The current version of the SDK is [3.0.0](https://github.com/saltedge/saltedge-ios/releases/tag/v3.0.0), and is in compliance with the Salt Edge API's [current version](https://docs.saltedge.com/#version_management). Any backward-incompatible changes in the API will result in changes to the SDK. ## License diff --git a/Salt Edge API Demo.xcodeproj/project.pbxproj b/Salt Edge API Demo.xcodeproj/project.pbxproj index 34e7619..d75fd9b 100644 --- a/Salt Edge API Demo.xcodeproj/project.pbxproj +++ b/Salt Edge API Demo.xcodeproj/project.pbxproj @@ -8,6 +8,9 @@ /* Begin PBXBuildFile section */ 0A1BEB7619EBD0E5000C0D64 /* PickerTVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A1BEB7519EBD0E5000C0D64 /* PickerTVC.m */; }; + 0A1DC3C71C62263D00001CD1 /* SELoginAttempt.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A1DC3C61C62263D00001CD1 /* SELoginAttempt.m */; }; + 0A1DC3CA1C6228D700001CD1 /* SELoginAttemptStage.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A1DC3C91C6228D700001CD1 /* SELoginAttemptStage.m */; }; + 0A1DC3CD1C6258A300001CD1 /* LoginAttemptsTVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A1DC3CC1C6258A300001CD1 /* LoginAttemptsTVC.m */; }; 0A3F86FF19A1F05E00B7E5E2 /* SEAPIRequestManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A3F86E019A1F05E00B7E5E2 /* SEAPIRequestManager.m */; }; 0A3F870019A1F05E00B7E5E2 /* NSString+SEModelsSerializingAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A3F86E419A1F05E00B7E5E2 /* NSString+SEModelsSerializingAdditions.m */; }; 0A3F870119A1F05E00B7E5E2 /* SEAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A3F86E719A1F05E00B7E5E2 /* SEAccount.m */; }; @@ -54,6 +57,7 @@ 0AD2C2E019E7EEF1003D2FD0 /* SEError.m in Sources */ = {isa = PBXBuildFile; fileRef = 0AD2C2DF19E7EEF1003D2FD0 /* SEError.m */; }; 0AE487131A02AC8B00F5CEBF /* NSURL+SECallbacksAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 0AE4870F1A02AC8B00F5CEBF /* NSURL+SECallbacksAdditions.m */; }; 0AE487141A02AC8B00F5CEBF /* SEWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0AE487111A02AC8B00F5CEBF /* SEWebView.m */; }; + 0AF891711C636A260078241B /* SingleLoginAttemptTVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0AF891701C636A260078241B /* SingleLoginAttemptTVC.m */; }; 0AF898811986632F00F1A270 /* NSURL+SECallbacksAdditionsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0AF898801986632F00F1A270 /* NSURL+SECallbacksAdditionsTests.m */; }; 0AF898841986633E00F1A270 /* ConnectWebViewVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0AF898831986633E00F1A270 /* ConnectWebViewVC.m */; }; 0AF898901986740200F1A270 /* TabBarVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 0AF8988F1986740200F1A270 /* TabBarVC.m */; }; @@ -75,6 +79,12 @@ /* Begin PBXFileReference section */ 0A1BEB7419EBD0E5000C0D64 /* PickerTVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PickerTVC.h; sourceTree = ""; }; 0A1BEB7519EBD0E5000C0D64 /* PickerTVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PickerTVC.m; sourceTree = ""; }; + 0A1DC3C51C62263D00001CD1 /* SELoginAttempt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SELoginAttempt.h; sourceTree = ""; }; + 0A1DC3C61C62263D00001CD1 /* SELoginAttempt.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SELoginAttempt.m; sourceTree = ""; }; + 0A1DC3C81C6228D700001CD1 /* SELoginAttemptStage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SELoginAttemptStage.h; sourceTree = ""; }; + 0A1DC3C91C6228D700001CD1 /* SELoginAttemptStage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SELoginAttemptStage.m; sourceTree = ""; }; + 0A1DC3CB1C6258A300001CD1 /* LoginAttemptsTVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoginAttemptsTVC.h; sourceTree = ""; }; + 0A1DC3CC1C6258A300001CD1 /* LoginAttemptsTVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoginAttemptsTVC.m; sourceTree = ""; }; 0A2A656119F7CC3D00BC5378 /* SELoginFetchingDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SELoginFetchingDelegate.h; sourceTree = ""; }; 0A3F86DF19A1F05E00B7E5E2 /* SEAPIRequestManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SEAPIRequestManager.h; sourceTree = ""; }; 0A3F86E019A1F05E00B7E5E2 /* SEAPIRequestManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SEAPIRequestManager.m; sourceTree = ""; }; @@ -156,6 +166,8 @@ 0AE487101A02AC8B00F5CEBF /* SEWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SEWebView.h; sourceTree = ""; }; 0AE487111A02AC8B00F5CEBF /* SEWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SEWebView.m; sourceTree = ""; }; 0AE487121A02AC8B00F5CEBF /* SEWebViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SEWebViewDelegate.h; sourceTree = ""; }; + 0AF8916F1C636A260078241B /* SingleLoginAttemptTVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SingleLoginAttemptTVC.h; sourceTree = ""; }; + 0AF891701C636A260078241B /* SingleLoginAttemptTVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SingleLoginAttemptTVC.m; sourceTree = ""; }; 0AF898801986632F00F1A270 /* NSURL+SECallbacksAdditionsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURL+SECallbacksAdditionsTests.m"; sourceTree = ""; }; 0AF898821986633E00F1A270 /* ConnectWebViewVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConnectWebViewVC.h; sourceTree = ""; }; 0AF898831986633E00F1A270 /* ConnectWebViewVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ConnectWebViewVC.m; sourceTree = ""; }; @@ -243,6 +255,10 @@ 0AD2C2DF19E7EEF1003D2FD0 /* SEError.m */, 0A3F86EA19A1F05E00B7E5E2 /* SELogin.h */, 0A3F86EB19A1F05E00B7E5E2 /* SELogin.m */, + 0A1DC3C51C62263D00001CD1 /* SELoginAttempt.h */, + 0A1DC3C61C62263D00001CD1 /* SELoginAttempt.m */, + 0A1DC3C81C6228D700001CD1 /* SELoginAttemptStage.h */, + 0A1DC3C91C6228D700001CD1 /* SELoginAttemptStage.m */, 0A3F86EC19A1F05E00B7E5E2 /* SEProvider.h */, 0A3F86ED19A1F05E00B7E5E2 /* SEProvider.m */, 0A3F86EE19A1F05E00B7E5E2 /* SEProviderField.h */, @@ -406,6 +422,10 @@ 0AF898831986633E00F1A270 /* ConnectWebViewVC.m */, 0AAB6D2519827ACD009DCDD5 /* LoginsTVC.h */, 0AAB6D2619827ACD009DCDD5 /* LoginsTVC.m */, + 0A1DC3CB1C6258A300001CD1 /* LoginAttemptsTVC.h */, + 0A1DC3CC1C6258A300001CD1 /* LoginAttemptsTVC.m */, + 0AF8916F1C636A260078241B /* SingleLoginAttemptTVC.h */, + 0AF891701C636A260078241B /* SingleLoginAttemptTVC.m */, 0A1BEB7419EBD0E5000C0D64 /* PickerTVC.h */, 0A1BEB7519EBD0E5000C0D64 /* PickerTVC.m */, 0AF8988E1986740200F1A270 /* TabBarVC.h */, @@ -509,7 +529,8 @@ 0AAB6CD919827AAA009DCDD5 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0510; + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 0720; ORGANIZATIONNAME = "Salt Edge"; TargetAttributes = { 0AAB6D0119827AAA009DCDD5 = { @@ -619,9 +640,11 @@ 0A1BEB7619EBD0E5000C0D64 /* PickerTVC.m in Sources */, 0A3F870019A1F05E00B7E5E2 /* NSString+SEModelsSerializingAdditions.m in Sources */, 0A939E9F19DA9F0E005BD28C /* TransactionTableViewCell.m in Sources */, + 0A1DC3CD1C6258A300001CD1 /* LoginAttemptsTVC.m in Sources */, 0A4DBC591A024C2900DC27C3 /* NSURL+SEQueryArgmuentsAdditions.m in Sources */, 0A3F870419A1F05E00B7E5E2 /* SEProvider.m in Sources */, 0AAB6D4F19827ACD009DCDD5 /* UIView+Framing.m in Sources */, + 0A1DC3CA1C6228D700001CD1 /* SELoginAttemptStage.m in Sources */, 0AAB6D5519827ACD009DCDD5 /* TransactionsTVC.m in Sources */, 0AAB6CF119827AAA009DCDD5 /* main.m in Sources */, 0AF898901986740200F1A270 /* TabBarVC.m in Sources */, @@ -634,11 +657,13 @@ 0A3F86FF19A1F05E00B7E5E2 /* SEAPIRequestManager.m in Sources */, 0A3F870619A1F05E00B7E5E2 /* SEProviderFieldOption.m in Sources */, 0AB068DA1A010E7E00596A3B /* SEAPIRequestManager+SEOAuthLoginHandlingAdditions.m in Sources */, + 0AF891711C636A260078241B /* SingleLoginAttemptTVC.m in Sources */, 0A3F870319A1F05E00B7E5E2 /* SELogin.m in Sources */, 0A3F870219A1F05E00B7E5E2 /* SEBaseModel.m in Sources */, 0A3F870A19A1F05E00B7E5E2 /* DateUtils.m in Sources */, 0AAB6D5319827ACD009DCDD5 /* LoginsTVC.m in Sources */, 0A6568A019F91DD0004A1EB1 /* UIControl+SELoginInputFieldsAdditions.m in Sources */, + 0A1DC3C71C62263D00001CD1 /* SELoginAttempt.m in Sources */, 0A3F870119A1F05E00B7E5E2 /* SEAccount.m in Sources */, 0A65689919F91CDF004A1EB1 /* CredentialsVC.m in Sources */, 0A65689819F91CDF004A1EB1 /* CreateLoginVC.m in Sources */, @@ -710,6 +735,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -724,7 +750,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; }; @@ -756,7 +782,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; }; @@ -768,11 +794,15 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CLANG_ENABLE_MODULES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Salt Edge API Demo/Salt Edge API Demo-Prefix.pch"; INFOPLIST_FILE = "Salt Edge API Demo/Salt Edge API Demo-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.saltedge.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; WRAPPER_EXTENSION = app; }; name = Debug; @@ -783,10 +813,13 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CLANG_ENABLE_MODULES = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Salt Edge API Demo/Salt Edge API Demo-Prefix.pch"; INFOPLIST_FILE = "Salt Edge API Demo/Salt Edge API Demo-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.saltedge.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -808,6 +841,7 @@ "$(inherited)", ); INFOPLIST_FILE = "Salt Edge API DemoTests/Salt Edge API DemoTests-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.saltedge.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUNDLE_LOADER)"; WRAPPER_EXTENSION = xctest; @@ -826,6 +860,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Salt Edge API Demo/Salt Edge API Demo-Prefix.pch"; INFOPLIST_FILE = "Salt Edge API DemoTests/Salt Edge API DemoTests-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = "com.saltedge.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUNDLE_LOADER)"; WRAPPER_EXTENSION = xctest; diff --git a/Salt Edge API Demo/AppDelegate.h b/Salt Edge API Demo/AppDelegate.h index b2cd763..6ca9ea9 100644 --- a/Salt Edge API Demo/AppDelegate.h +++ b/Salt Edge API Demo/AppDelegate.h @@ -3,22 +3,21 @@ // SaltEdge API Demo // // Created by nemesis on 7/22/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import @class TabBarVC; -static NSString* const kLoginSecretsDefaultsKey = @"LoginSecretsArray"; -static NSString* const kCustomerIdDefaultsKey = @"CustomerIdKey"; +static NSString* const kLoginSecretsDefaultsKey = @"LoginSecretsArray"; +static NSString* const kCustomerSecretDefaultsKey = @"CustomerSecretKey"; @interface AppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @property (strong, readonly) TabBarVC* tabBar; @property (strong, nonatomic) NSSet* providers; -@property (strong, nonatomic) NSString* customerId; + (instancetype)delegate; - (NSString*)applicationURLString; diff --git a/Salt Edge API Demo/AppDelegate.m b/Salt Edge API Demo/AppDelegate.m index 038ec8a..04c8e7c 100644 --- a/Salt Edge API Demo/AppDelegate.m +++ b/Salt Edge API Demo/AppDelegate.m @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/22/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import "AppDelegate.h" @@ -38,6 +38,8 @@ - (NSString*)applicationURLString - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [self setupAppearance]; + static NSString* const clientId = nil; // insert your client ID here static NSString* const appSecret = nil; // insert your app secret here static NSString* const customerIdentifier = nil; // insert customer identifier here @@ -55,57 +57,36 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [SVProgressHUD dismiss]; }; - __block NSString* customerId = [[NSUserDefaults standardUserDefaults] stringForKey:kCustomerIdDefaultsKey]; - if (!customerId) { + __block NSString* customerSecret = [[NSUserDefaults standardUserDefaults] stringForKey:kCustomerSecretDefaultsKey]; + if (!customerSecret) { [SVProgressHUD showWithStatus:@"Creating customer..."]; SEAPIRequestManager* manager = [SEAPIRequestManager manager]; [manager createCustomerWithIdentifier:customerIdentifier success:^(NSDictionary* responseObject) { - customerId = responseObject[kDataKey][kCustomerIdKey]; - [[NSUserDefaults standardUserDefaults] setObject:customerId forKey:kCustomerIdDefaultsKey]; + customerSecret = responseObject[kDataKey][kCustomerSecretKey]; + [[NSUserDefaults standardUserDefaults] setObject:customerSecret forKey:kCustomerSecretDefaultsKey]; [[NSUserDefaults standardUserDefaults] synchronize]; - self.customerId = customerId; + [SEAPIRequestManager linkCustomerSecret:customerSecret]; setWindowRootViewController(); } failure:^(SEError* error) { - [SVProgressHUD showErrorWithStatus:error.message]; + [SVProgressHUD showErrorWithStatus:error.errorMessage]; }]; } else { - self.customerId = customerId; + [SEAPIRequestManager linkCustomerSecret:customerSecret]; setWindowRootViewController(); } return YES; } -- (CreateLoginVC*)createController -{ - return [self.tabBar.viewControllers[1] viewControllers][0]; -} - -- (void)applicationWillResignActive:(UIApplication *)application -{ - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. -} - -- (void)applicationDidEnterBackground:(UIApplication *)application +- (void)setupAppearance { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + [SVProgressHUD setBackgroundColor:[UIColor blackColor]]; + [SVProgressHUD setForegroundColor:[UIColor whiteColor]]; } -- (void)applicationWillEnterForeground:(UIApplication *)application -{ - // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. -} - -- (void)applicationDidBecomeActive:(UIApplication *)application -{ - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. -} - -- (void)applicationWillTerminate:(UIApplication *)application +- (CreateLoginVC*)createController { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + return [self.tabBar.viewControllers[1] viewControllers][0]; } - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation diff --git a/Salt Edge API Demo/Categories/UIControl+SELoginInputFieldsAdditions.h b/Salt Edge API Demo/Categories/UIControl+SELoginInputFieldsAdditions.h index 1c29d67..a12b2ed 100755 --- a/Salt Edge API Demo/Categories/UIControl+SELoginInputFieldsAdditions.h +++ b/Salt Edge API Demo/Categories/UIControl+SELoginInputFieldsAdditions.h @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/22/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import diff --git a/Salt Edge API Demo/Categories/UIControl+SELoginInputFieldsAdditions.m b/Salt Edge API Demo/Categories/UIControl+SELoginInputFieldsAdditions.m index 32ac565..6221a4f 100755 --- a/Salt Edge API Demo/Categories/UIControl+SELoginInputFieldsAdditions.m +++ b/Salt Edge API Demo/Categories/UIControl+SELoginInputFieldsAdditions.m @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/22/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import "UIControl+SELoginInputFieldsAdditions.h" diff --git a/Salt Edge API Demo/Controllers/AccountsTVC.h b/Salt Edge API Demo/Controllers/AccountsTVC.h index 0e83937..4557130 100644 --- a/Salt Edge API Demo/Controllers/AccountsTVC.h +++ b/Salt Edge API Demo/Controllers/AccountsTVC.h @@ -4,7 +4,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/21/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import diff --git a/Salt Edge API Demo/Controllers/AccountsTVC.m b/Salt Edge API Demo/Controllers/AccountsTVC.m index df3c213..f602a28 100644 --- a/Salt Edge API Demo/Controllers/AccountsTVC.m +++ b/Salt Edge API Demo/Controllers/AccountsTVC.m @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/21/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import "AccountsTVC.h" @@ -21,15 +21,17 @@ #import "CreateLoginVC.h" #import "SELoginFetchingDelegate.h" #import "SEProvider.h" +#import "LoginAttemptsTVC.h" typedef NS_ENUM(NSUInteger, SELoginActionMethod){ SELoginActionMethodAPI = 0, SELoginActionMethodWebView }; -static NSString* const kLoginRefreshAction = @"Refresh"; -static NSString* const kLoginReconnectAction = @"Reconnect"; -static NSString* const kLoginRemoveAction = @"Remove"; +static NSString* const kLoginRefreshAction = @"Refresh"; +static NSString* const kLoginReconnectAction = @"Reconnect"; +static NSString* const kLoginViewAttemptsAction = @"View Attempts"; +static NSString* const kLoginRemoveAction = @"Remove"; static NSString* const kLoginActionMethodWebView = @"Web view"; static NSString* const kLoginActionMethodAPI = @"API"; @@ -69,7 +71,7 @@ - (void)setup - (void)actionsPressed { - UIActionSheet* actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:kLoginRemoveAction otherButtonTitles:kLoginReconnectAction, kLoginRefreshAction, nil]; + UIActionSheet* actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:kLoginRemoveAction otherButtonTitles:kLoginReconnectAction, kLoginRefreshAction, kLoginViewAttemptsAction, nil]; [actionSheet showInView:self.view]; } @@ -91,12 +93,12 @@ - (void)reloadAccountsTableView [SVProgressHUD dismiss]; } failure:^(SEError* error) { NSLog(@"Error: %@", error); - [SVProgressHUD showErrorWithStatus:error.message]; + [SVProgressHUD showErrorWithStatus:error.errorMessage]; }]; } failure:^(SEError* error) { NSLog(@"Error: %@", error); - [SVProgressHUD showErrorWithStatus:error.message]; + [SVProgressHUD showErrorWithStatus:error.errorMessage]; }]; } @@ -105,6 +107,13 @@ - (void)showWebViewOrAPIAlert [[[UIAlertView alloc] initWithTitle:@"Choose a method for the action" message:nil delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:kLoginActionMethodWebView, kLoginActionMethodAPI, nil] show]; } +- (void)showLoginAttempts +{ + LoginAttemptsTVC* loginAttempts = [self.storyboard instantiateViewControllerWithIdentifier:@"LoginAttemptsTVC"]; + loginAttempts.login = self.login; + [self.navigationController pushViewController:loginAttempts animated:YES]; +} + - (void)refreshCurrentLoginViaAPI { [SVProgressHUD showWithStatus:@"Refreshing..." maskType:SVProgressHUDMaskTypeGradient]; @@ -118,7 +127,7 @@ - (void)refreshCurrentLoginViaAPI } } failure:^(SEError* error) { - [SVProgressHUD showErrorWithStatus:error.message]; + [SVProgressHUD showErrorWithStatus:error.errorMessage]; } delegate:self]; } else { [manager refreshOAuthLoginWithSecret:self.login.secret @@ -127,7 +136,7 @@ - (void)refreshCurrentLoginViaAPI [[UIApplication sharedApplication] openURL:[NSURL URLWithString:responseObject[kDataKey][kRedirectURLKey]]]; } failure:^(SEError* error) { - [SVProgressHUD showErrorWithStatus:error.message]; + [SVProgressHUD showErrorWithStatus:error.errorMessage]; }]; } } @@ -178,7 +187,7 @@ - (void)removeLogin [SVProgressHUD showErrorWithStatus:@"Couldn't remove login"]; } } failure:^(SEError* error) { - [SVProgressHUD showErrorWithStatus:error.message]; + [SVProgressHUD showErrorWithStatus:error.errorMessage]; }]; } @@ -232,6 +241,8 @@ - (void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSI if ([buttonTitle isEqualToString:kLoginRefreshAction] || [buttonTitle isEqualToString:kLoginReconnectAction]) { self.desiredLoginAction = buttonTitle; [self showWebViewOrAPIAlert]; + } else if ([buttonTitle isEqualToString:kLoginViewAttemptsAction]) { + [self showLoginAttempts]; } else if ([buttonTitle isEqualToString:kLoginRemoveAction]) { [self removeLogin]; [self.navigationController popViewControllerAnimated:YES]; diff --git a/Salt Edge API Demo/Controllers/ConnectWebViewVC.h b/Salt Edge API Demo/Controllers/ConnectWebViewVC.h index 26f0a50..1b2dadc 100644 --- a/Salt Edge API Demo/Controllers/ConnectWebViewVC.h +++ b/Salt Edge API Demo/Controllers/ConnectWebViewVC.h @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/17/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import diff --git a/Salt Edge API Demo/Controllers/ConnectWebViewVC.m b/Salt Edge API Demo/Controllers/ConnectWebViewVC.m index dada11d..d4149c3 100644 --- a/Salt Edge API Demo/Controllers/ConnectWebViewVC.m +++ b/Salt Edge API Demo/Controllers/ConnectWebViewVC.m @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/17/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import "ConnectWebViewVC.h" @@ -109,7 +109,7 @@ - (void)fetchProviders [self showProviders]; [SVProgressHUD dismiss]; } failure:^(SEError* error) { - [SVProgressHUD showErrorWithStatus:error.message]; + [SVProgressHUD showErrorWithStatus:error.errorMessage]; }]; } } @@ -134,8 +134,7 @@ - (void)requestToken SEAPIRequestManager* manager = [SEAPIRequestManager manager]; [SVProgressHUD showWithStatus:@"Requesting token..." maskType:SVProgressHUDMaskTypeGradient]; if (!self.login) { - NSString* customerId = [AppDelegate delegate].customerId; - [manager requestCreateTokenWithParameters:@{ @"country_code" : self.provider.countryCode, @"provider_code" : self.provider.code, @"return_to" : @"http://httpbin.org", @"customer_id" : customerId } success:^(NSDictionary* responseObject) { + [manager requestCreateTokenWithParameters:@{ @"country_code" : self.provider.countryCode, @"provider_code" : self.provider.code, @"return_to" : @"http://httpbin.org" } success:^(NSDictionary* responseObject) { [self loadConnectPageWithURLString:responseObject[kDataKey][kConnectURLKey]]; } failure:^(SEError* error) { NSLog(@"%@", error); @@ -145,14 +144,14 @@ - (void)requestToken [self loadConnectPageWithURLString:responseObject[kDataKey][kConnectURLKey]]; } failure:^(SEError* error) { NSLog(@"%@", error); - [SVProgressHUD showErrorWithStatus:error.message]; + [SVProgressHUD showErrorWithStatus:error.errorMessage]; }]; } else { [manager requestReconnectTokenForLoginSecret:self.login.secret parameters:@{ @"return_to": @"http://httpbin.org" } success:^(NSDictionary* responseObject) { [self loadConnectPageWithURLString:responseObject[kDataKey][kConnectURLKey]]; } failure:^(SEError* error) { NSLog(@"%@", error); - [SVProgressHUD showErrorWithStatus:error.message]; + [SVProgressHUD showErrorWithStatus:error.errorMessage]; }]; } } @@ -197,8 +196,7 @@ - (void)switchToLoginsViewController - (void)webView:(SEWebView *)webView receivedCallbackWithResponse:(NSDictionary *)response { - NSString* loginState = response[SELoginDataKey][SELoginStateKey]; - + NSString* loginState = response[SELoginDataKey][SELoginStageKey]; if ([loginState isEqualToString:SELoginStateSuccess]) { [self switchToLoginsViewController]; [SVProgressHUD dismiss]; @@ -211,7 +209,7 @@ - (void)webView:(SEWebView *)webView receivedCallbackWithResponse:(NSDictionary [loginSecrets addObject:loginSecret]; [[NSUserDefaults standardUserDefaults] setObject:[loginSecrets allObjects] forKey:kLoginSecretsDefaultsKey]; [[NSUserDefaults standardUserDefaults] synchronize]; - if (self.login && !self.login.interactive.boolValue) { + if (self.login && !self.login.lastAttempt.interactive.boolValue) { [SVProgressHUD showWithStatus:@"Loading..." maskType:SVProgressHUDMaskTypeGradient]; } } else if ([loginState isEqualToString:SELoginStateError]) { diff --git a/Salt Edge API Demo/Controllers/CreateLoginVC.h b/Salt Edge API Demo/Controllers/CreateLoginVC.h index 9d6047e..b65df3b 100755 --- a/Salt Edge API Demo/Controllers/CreateLoginVC.h +++ b/Salt Edge API Demo/Controllers/CreateLoginVC.h @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/22/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import diff --git a/Salt Edge API Demo/Controllers/CreateLoginVC.m b/Salt Edge API Demo/Controllers/CreateLoginVC.m index 3ab5feb..f7eecf8 100755 --- a/Salt Edge API Demo/Controllers/CreateLoginVC.m +++ b/Salt Edge API Demo/Controllers/CreateLoginVC.m @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/22/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import "CreateLoginVC.h" @@ -80,7 +80,7 @@ - (void)fetchProviders [self showProviders]; [SVProgressHUD dismiss]; } failure:^(SEError* error) { - [SVProgressHUD showErrorWithStatus:error.message]; + [SVProgressHUD showErrorWithStatus:error.errorMessage]; }]; } } @@ -113,7 +113,7 @@ - (void)fetchProviderFieldsWithProviderCode:(NSString*)code [SVProgressHUD dismiss]; } failure:^(SEError* error) { - [SVProgressHUD showErrorWithStatus:error.message]; + [SVProgressHUD showErrorWithStatus:error.errorMessage]; }]; } @@ -229,8 +229,7 @@ - (NSDictionary*)credentials - (void)createLogin { NSMutableDictionary* parameters = @{ kCountryCodeKey : self.provider.countryCode, - kProviderCodeKey : self.provider.code, - kCustomerIdKey : [AppDelegate delegate].customerId, + kProviderCodeKey : self.provider.code }.mutableCopy; [SVProgressHUD showWithStatus:@"Creating login..." maskType:SVProgressHUDMaskTypeGradient]; @@ -243,7 +242,7 @@ - (void)createLogin [SVProgressHUD showWithStatus:@"Fetching login..." maskType:SVProgressHUDMaskTypeGradient]; } failure:^(SEError* error) { - [SVProgressHUD showErrorWithStatus:error.message]; + [SVProgressHUD showErrorWithStatus:error.errorMessage]; } delegate:self]; } else { parameters[kReturnToKey] = [[AppDelegate delegate] applicationURLString]; @@ -252,7 +251,7 @@ - (void)createLogin [[UIApplication sharedApplication] openURL:[NSURL URLWithString:responseObject[kDataKey][kRedirectURLKey]]]; } failure:^(SEError* error) { - [SVProgressHUD showErrorWithStatus:error.message]; + [SVProgressHUD showErrorWithStatus:error.errorMessage]; } delegate:self]; } } @@ -268,7 +267,7 @@ - (void)reconnectLogin credentials:credentialsDictionary success:nil failure:^(SEError* error) { - [SVProgressHUD showErrorWithStatus:error.message]; + [SVProgressHUD showErrorWithStatus:error.errorMessage]; } delegate:self]; } else { [manager reconnectOAuthLoginWithSecret:self.login.secret @@ -277,7 +276,7 @@ - (void)reconnectLogin [[UIApplication sharedApplication] openURL:[NSURL URLWithString:responseObject[kDataKey][kRedirectURLKey]]]; } failure:^(SEError* error) { - [SVProgressHUD showErrorWithStatus:error.message]; + [SVProgressHUD showErrorWithStatus:error.errorMessage]; }]; } } @@ -326,10 +325,10 @@ - (void)loginRequestedInteractiveInput:(SELogin*)login { CredentialsVC* credentialsVC = [self.storyboard instantiateViewControllerWithIdentifier:@"CredentialsVC"]; NSPredicate* predicate = [NSPredicate predicateWithBlock:^BOOL(SEProviderField* field, NSDictionary* bindings) { - return [login.interactiveFieldsNames containsObject:field.name]; + return [login.lastAttempt.lastStage.interactiveFieldsNames containsObject:field.name]; }]; credentialsVC.credentialFields = [self.provider.interactiveFields filteredArrayUsingPredicate:predicate]; - credentialsVC.interactiveHtml = login.interactiveHtml; + credentialsVC.interactiveHtml = login.lastAttempt.lastStage.interactiveHtml; credentialsVC.completionBlock = ^(NSDictionary* credentials) { [SVProgressHUD showWithStatus:@"Sending credentials..." maskType:SVProgressHUDMaskTypeGradient]; SEAPIRequestManager* manager = [SEAPIRequestManager manager]; @@ -341,7 +340,7 @@ - (void)loginRequestedInteractiveInput:(SELogin*)login }]; } failure:^(SEError* error) { - [SVProgressHUD showErrorWithStatus:error.message]; + [SVProgressHUD showErrorWithStatus:error.errorMessage]; } delegate: self]; }; diff --git a/Salt Edge API Demo/Controllers/CredentialsVC.h b/Salt Edge API Demo/Controllers/CredentialsVC.h index ae27eb8..2107611 100755 --- a/Salt Edge API Demo/Controllers/CredentialsVC.h +++ b/Salt Edge API Demo/Controllers/CredentialsVC.h @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/23/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import diff --git a/Salt Edge API Demo/Controllers/CredentialsVC.m b/Salt Edge API Demo/Controllers/CredentialsVC.m index 251807f..da60eb1 100755 --- a/Salt Edge API Demo/Controllers/CredentialsVC.m +++ b/Salt Edge API Demo/Controllers/CredentialsVC.m @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/23/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import "CredentialsVC.h" diff --git a/Salt Edge API Demo/Controllers/LoginAttemptsTVC.h b/Salt Edge API Demo/Controllers/LoginAttemptsTVC.h new file mode 100644 index 0000000..96db77b --- /dev/null +++ b/Salt Edge API Demo/Controllers/LoginAttemptsTVC.h @@ -0,0 +1,17 @@ +// +// LoginAttemptsTVC.h +// Salt Edge API Demo +// +// Created by Constantin Lungu on 2/3/16. +// Copyright © 2016 Salt Edge. All rights reserved. +// + +#import + +@class SELogin; + +@interface LoginAttemptsTVC : UITableViewController + +@property (nonatomic, strong) SELogin* login; + +@end diff --git a/Salt Edge API Demo/Controllers/LoginAttemptsTVC.m b/Salt Edge API Demo/Controllers/LoginAttemptsTVC.m new file mode 100644 index 0000000..b8ecf26 --- /dev/null +++ b/Salt Edge API Demo/Controllers/LoginAttemptsTVC.m @@ -0,0 +1,104 @@ +// +// LoginAttemptsTVC.m +// Salt Edge API Demo +// +// Created by Constantin Lungu on 2/3/16. +// Copyright © 2016 Salt Edge. All rights reserved. +// + +#import "LoginAttemptsTVC.h" +#import "SELoginAttempt.h" +#import "SVProgressHUD.h" +#import "SEAPIRequestManager.h" +#import "SELogin.h" +#import "SEError.h" +#import "SingleLoginAttemptTVC.h" + +@interface LoginAttemptsTVC () + +@property (nonatomic, strong) NSArray* attempts; + +@end + +static NSString* const kLoginAttemptTableViewCellReuseIdentifier = @"LoginAttemptTableViewCell"; + +@implementation LoginAttemptsTVC + +#pragma mark - View Controller Lifecycle + +- (void)viewDidLoad +{ + [super viewDidLoad]; + [self.tableView setTableFooterView:[[UIView alloc] initWithFrame:CGRectZero]]; + [self reloadLoginAttempts]; +} + +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return self.attempts.count; +} + +- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:kLoginAttemptTableViewCellReuseIdentifier forIndexPath:indexPath]; + SELoginAttempt* attempt = self.attempts[indexPath.row]; + NSDate* lastRequestDate = [self nonNullLoginActionDateForAttempt:attempt]; + cell.textLabel.text = lastRequestDate.description; + cell.detailTextLabel.textColor = [self statusColorForLoginAttempt:attempt]; + cell.detailTextLabel.text = [self statusTextForLoginAttempt:attempt]; + return cell; +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + SELoginAttempt* selectedAttempt = self.attempts[indexPath.row]; + SingleLoginAttemptTVC* attemptVC = [self.storyboard instantiateViewControllerWithIdentifier:@"SingleLoginAttemptTVC"]; + attemptVC.attempt = selectedAttempt; + attemptVC.loginSecret = self.login.secret; + [self.navigationController pushViewController:attemptVC animated:YES]; +} + +#pragma mark - Helper methods + +- (NSDate*)nonNullLoginActionDateForAttempt:(SELoginAttempt*)attempt +{ + return attempt.successAt ? attempt.successAt : attempt.failAt; +} + +- (UIColor*)statusColorForLoginAttempt:(SELoginAttempt*)attempt +{ + if (attempt.successAt) { + return [UIColor colorWithRed:91.0/255.0 green:182.0/255.0 blue:92.0/255.0 alpha:1.0]; + } + return [UIColor colorWithRed:212.0/255.0 green:72.0/255.0 blue:71.0/255.0 alpha:1.0]; +} + +- (NSString*)statusTextForLoginAttempt:(SELoginAttempt*)attempt +{ + return attempt.successAt ? @"Success" : @"Error"; +} + +- (void)reloadLoginAttempts +{ + [SVProgressHUD showWithStatus:@"Loading attempts..." maskType:SVProgressHUDMaskTypeGradient]; + + SEAPIRequestManager* manager = [SEAPIRequestManager manager]; + [manager fetchAttemptsForLoginWithSecret:self.login.secret + success:^(NSArray* attempts) { + self.attempts = attempts; + [self.tableView reloadData]; + [SVProgressHUD dismiss]; + }failure:^(SEError* error) { + NSLog(@"Error: %@", error); + [SVProgressHUD showErrorWithStatus:error.errorMessage]; + }]; +} + +@end diff --git a/Salt Edge API Demo/Controllers/LoginsTVC.h b/Salt Edge API Demo/Controllers/LoginsTVC.h index 81bbdee..4573cc1 100644 --- a/Salt Edge API Demo/Controllers/LoginsTVC.h +++ b/Salt Edge API Demo/Controllers/LoginsTVC.h @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/21/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import diff --git a/Salt Edge API Demo/Controllers/LoginsTVC.m b/Salt Edge API Demo/Controllers/LoginsTVC.m index 67f0636..70e0f67 100644 --- a/Salt Edge API Demo/Controllers/LoginsTVC.m +++ b/Salt Edge API Demo/Controllers/LoginsTVC.m @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/21/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import "LoginsTVC.h" @@ -90,7 +90,7 @@ - (void)reloadLoginsTableViewController self.isLoadingLogins = NO; } } failure:^(SEError* error) { - [SVProgressHUD showErrorWithStatus:error.message]; + [SVProgressHUD showErrorWithStatus:error.errorMessage]; self.isLoadingLogins = NO; }]; } @@ -127,7 +127,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kLoginTableViewCellReuseIdentifier forIndexPath:indexPath]; SELogin* theLogin = self.logins[indexPath.row]; cell.textLabel.text = theLogin.providerName; - cell.detailTextLabel.text = theLogin.customerEmail; + cell.detailTextLabel.text = theLogin.status; return cell; } diff --git a/Salt Edge API Demo/Controllers/PickerTVC.h b/Salt Edge API Demo/Controllers/PickerTVC.h index 014e6e1..7250116 100755 --- a/Salt Edge API Demo/Controllers/PickerTVC.h +++ b/Salt Edge API Demo/Controllers/PickerTVC.h @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/22/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import diff --git a/Salt Edge API Demo/Controllers/PickerTVC.m b/Salt Edge API Demo/Controllers/PickerTVC.m index 9e4d7c7..9edcd0d 100755 --- a/Salt Edge API Demo/Controllers/PickerTVC.m +++ b/Salt Edge API Demo/Controllers/PickerTVC.m @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/22/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import "PickerTVC.h" diff --git a/Salt Edge API Demo/Controllers/SingleLoginAttemptTVC.h b/Salt Edge API Demo/Controllers/SingleLoginAttemptTVC.h new file mode 100644 index 0000000..eb6ed5b --- /dev/null +++ b/Salt Edge API Demo/Controllers/SingleLoginAttemptTVC.h @@ -0,0 +1,18 @@ +// +// SingleLoginAttemptTVC.h +// Salt Edge API Demo +// +// Created by Constantin Lungu on 2/4/16. +// Copyright © 2016 Salt Edge. All rights reserved. +// + +#import + +@class SELoginAttempt; + +@interface SingleLoginAttemptTVC : UITableViewController + +@property (nonatomic, strong) SELoginAttempt* attempt; +@property (nonatomic, strong) NSString* loginSecret; + +@end diff --git a/Salt Edge API Demo/Controllers/SingleLoginAttemptTVC.m b/Salt Edge API Demo/Controllers/SingleLoginAttemptTVC.m new file mode 100644 index 0000000..dcf3038 --- /dev/null +++ b/Salt Edge API Demo/Controllers/SingleLoginAttemptTVC.m @@ -0,0 +1,77 @@ +// +// SingleLoginAttemptTVC.m +// Salt Edge API Demo +// +// Created by Constantin Lungu on 2/4/16. +// Copyright © 2016 Salt Edge. All rights reserved. +// + +#import "SingleLoginAttemptTVC.h" +#import "SEAPIRequestManager.h" +#import "SELoginAttempt.h" +#import "SELoginAttemptStage.h" +#import "SVProgressHUD.h" +#import "SEError.h" + +static NSString* const kAttemptStageCellReuseIdentifier = @"AttemptStageTableViewCell"; +static NSString* const kStageNameKey = @"name"; +static NSString* const kStageCreatedAtKey = @"created_at"; + +@interface SingleLoginAttemptTVC () + +@property (nonatomic, strong) NSArray* stages; + +@end + +@implementation SingleLoginAttemptTVC + +- (void)viewDidLoad +{ + [super viewDidLoad]; + self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero]; + [self requestFullLoginAttempt]; +} + +- (void)requestFullLoginAttempt +{ + [SVProgressHUD showWithStatus:@"Loading attempt..."]; + + NSArray* (^sortStagesByCreatedAt)(NSArray*) = ^NSArray*(NSArray* stages) { + return [stages sortedArrayUsingComparator:^NSComparisonResult(SELoginAttemptStage* first, SELoginAttemptStage* second) { + return [first.createdAt compare:second.createdAt]; + }]; + }; + SEAPIRequestManager* manager = [SEAPIRequestManager manager]; + [manager fetchAttemptWithId:self.attempt.id + forLoginWithSecret:self.loginSecret + success:^(SELoginAttempt* attempt) { + self.stages = sortStagesByCreatedAt(attempt.stages); + [self.tableView reloadData]; + [SVProgressHUD dismiss]; + } failure:^(SEError* error) { + [SVProgressHUD showErrorWithStatus:error.errorMessage]; + }]; +} + +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return self.stages.count; +} + +- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:kAttemptStageCellReuseIdentifier forIndexPath:indexPath]; + SELoginAttemptStage* stage = self.stages[indexPath.row]; + cell.textLabel.text = stage.name; + cell.detailTextLabel.text = stage.createdAt.description; + return cell; +} + +@end diff --git a/Salt Edge API Demo/Controllers/TabBarVC.h b/Salt Edge API Demo/Controllers/TabBarVC.h index 71ac330..e0e902d 100644 --- a/Salt Edge API Demo/Controllers/TabBarVC.h +++ b/Salt Edge API Demo/Controllers/TabBarVC.h @@ -3,7 +3,7 @@ // Salt Edge API Demo // // Created by nemesis on 7/28/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import diff --git a/Salt Edge API Demo/Controllers/TabBarVC.m b/Salt Edge API Demo/Controllers/TabBarVC.m index a26372c..b05ed27 100644 --- a/Salt Edge API Demo/Controllers/TabBarVC.m +++ b/Salt Edge API Demo/Controllers/TabBarVC.m @@ -3,7 +3,7 @@ // Salt Edge API Demo // // Created by nemesis on 7/28/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import "TabBarVC.h" diff --git a/Salt Edge API Demo/Controllers/TransactionsTVC.h b/Salt Edge API Demo/Controllers/TransactionsTVC.h index 6c98104..d5c85f9 100644 --- a/Salt Edge API Demo/Controllers/TransactionsTVC.h +++ b/Salt Edge API Demo/Controllers/TransactionsTVC.h @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/21/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import diff --git a/Salt Edge API Demo/Controllers/TransactionsTVC.m b/Salt Edge API Demo/Controllers/TransactionsTVC.m index bbcb43e..15c80c2 100644 --- a/Salt Edge API Demo/Controllers/TransactionsTVC.m +++ b/Salt Edge API Demo/Controllers/TransactionsTVC.m @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/21/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import "TransactionsTVC.h" @@ -54,7 +54,7 @@ - (void)reloadTransactionsTableView [SVProgressHUD dismiss]; } failure:^(SEError* error) { NSLog(@"%@", error); - [SVProgressHUD showErrorWithStatus:error.message]; + [SVProgressHUD showErrorWithStatus:error.errorMessage]; }]; } diff --git a/Salt Edge API Demo/Controls/OptionSelectButton.h b/Salt Edge API Demo/Controls/OptionSelectButton.h index 0268270..1842248 100755 --- a/Salt Edge API Demo/Controls/OptionSelectButton.h +++ b/Salt Edge API Demo/Controls/OptionSelectButton.h @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/23/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import diff --git a/Salt Edge API Demo/Controls/OptionSelectButton.m b/Salt Edge API Demo/Controls/OptionSelectButton.m index 77bf415..544eb9c 100755 --- a/Salt Edge API Demo/Controls/OptionSelectButton.m +++ b/Salt Edge API Demo/Controls/OptionSelectButton.m @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/23/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import "OptionSelectButton.h" diff --git a/Salt Edge API Demo/Main.storyboard b/Salt Edge API Demo/Main.storyboard index 5875165..ac8426c 100644 --- a/Salt Edge API Demo/Main.storyboard +++ b/Salt Edge API Demo/Main.storyboard @@ -75,7 +75,51 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -89,7 +133,7 @@ - + @@ -125,7 +169,7 @@ - + @@ -139,7 +183,7 @@ - + @@ -153,7 +197,7 @@ - + @@ -169,6 +213,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -211,7 +299,7 @@ - + diff --git a/Salt Edge API Demo/Protocols/LoginsTVCDelegate.h b/Salt Edge API Demo/Protocols/LoginsTVCDelegate.h index c560667..65ecc3f 100644 --- a/Salt Edge API Demo/Protocols/LoginsTVCDelegate.h +++ b/Salt Edge API Demo/Protocols/LoginsTVCDelegate.h @@ -3,7 +3,7 @@ // Salt Edge API Demo // // Created by nemesis on 8/18/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import diff --git a/Salt Edge API Demo/Protocols/PickerDelegate.h b/Salt Edge API Demo/Protocols/PickerDelegate.h index 9690a36..08ddb2b 100755 --- a/Salt Edge API Demo/Protocols/PickerDelegate.h +++ b/Salt Edge API Demo/Protocols/PickerDelegate.h @@ -3,7 +3,7 @@ // SaltEdge API Demo // // Created by nemesis on 7/23/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import diff --git a/Salt Edge API Demo/Salt Edge API Demo-Info.plist b/Salt Edge API Demo/Salt Edge API Demo-Info.plist index e6a3923..5c92645 100644 --- a/Salt Edge API Demo/Salt Edge API Demo-Info.plist +++ b/Salt Edge API Demo/Salt Edge API Demo-Info.plist @@ -9,7 +9,7 @@ CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIdentifier - com.saltedge.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -23,12 +23,12 @@ CFBundleURLTypes + CFBundleURLName + com.saltedge.Salt-Edge-API-Demo CFBundleURLSchemes SaltEdge-API-Demo - CFBundleURLName - com.saltedge.Salt-Edge-API-Demo CFBundleVersion diff --git a/Salt Edge API Demo/Table View Cells/TransactionTableViewCell.h b/Salt Edge API Demo/Table View Cells/TransactionTableViewCell.h index 83aaf40..3aec8e6 100644 --- a/Salt Edge API Demo/Table View Cells/TransactionTableViewCell.h +++ b/Salt Edge API Demo/Table View Cells/TransactionTableViewCell.h @@ -3,7 +3,7 @@ // Salt Edge API Demo // // Created by nemesis on 9/30/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import diff --git a/Salt Edge API Demo/Table View Cells/TransactionTableViewCell.m b/Salt Edge API Demo/Table View Cells/TransactionTableViewCell.m index 9871755..ab1278b 100644 --- a/Salt Edge API Demo/Table View Cells/TransactionTableViewCell.m +++ b/Salt Edge API Demo/Table View Cells/TransactionTableViewCell.m @@ -3,7 +3,7 @@ // Salt Edge API Demo // // Created by nemesis on 9/30/14. -// Copyright (c) 2015 Salt Edge. All rights reserved. +// Copyright (c) 2016 Salt Edge. All rights reserved. // #import "TransactionTableViewCell.h" diff --git a/Salt Edge API Demo/Table View Cells/TransactionTableViewCell.xib b/Salt Edge API Demo/Table View Cells/TransactionTableViewCell.xib index 1848de1..c8ebde3 100644 --- a/Salt Edge API Demo/Table View Cells/TransactionTableViewCell.xib +++ b/Salt Edge API Demo/Table View Cells/TransactionTableViewCell.xib @@ -1,8 +1,8 @@ - + - + @@ -11,7 +11,7 @@ - +