Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix invalid JSON error when deleting Card from Customer #992

Merged
merged 3 commits into from
Jul 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Stripe.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,11 @@
8BD87B951EFB1CB100269C2B /* STPSourceVerificationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD87B941EFB1CB100269C2B /* STPSourceVerificationTest.m */; };
8BE5AE8B1EF8905B0081A33C /* STPCardParamsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BE5AE8A1EF8905B0081A33C /* STPCardParamsTest.m */; };
B318518320BE011700EE8C0F /* STPColorUtilsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B318518220BE011700EE8C0F /* STPColorUtilsTest.m */; };
B32B175E20F6D2C4000D6EF8 /* STPGenericStripeObject.h in Headers */ = {isa = PBXBuildFile; fileRef = B32B175C20F6D2C4000D6EF8 /* STPGenericStripeObject.h */; };
B32B175F20F6D2C4000D6EF8 /* STPGenericStripeObject.h in Headers */ = {isa = PBXBuildFile; fileRef = B32B175C20F6D2C4000D6EF8 /* STPGenericStripeObject.h */; };
B32B176020F6D2C4000D6EF8 /* STPGenericStripeObject.m in Sources */ = {isa = PBXBuildFile; fileRef = B32B175D20F6D2C4000D6EF8 /* STPGenericStripeObject.m */; };
B32B176120F6D2C4000D6EF8 /* STPGenericStripeObject.m in Sources */ = {isa = PBXBuildFile; fileRef = B32B175D20F6D2C4000D6EF8 /* STPGenericStripeObject.m */; };
B32B176320F6D722000D6EF8 /* STPGenericStripeObjectTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B32B176220F6D722000D6EF8 /* STPGenericStripeObjectTest.m */; };
B3302F462006FBA7005DDBE9 /* STPConnectAccountParamsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B3302F452006FBA7005DDBE9 /* STPConnectAccountParamsTest.m */; };
B3302F4C200700AB005DDBE9 /* STPLegalEntityParamsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B3302F4B200700AB005DDBE9 /* STPLegalEntityParamsTest.m */; };
B347DD481FE35423006B3BAC /* STPValidatedTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = B347DD461FE35423006B3BAC /* STPValidatedTextField.h */; };
Expand Down Expand Up @@ -1063,6 +1068,9 @@
8BD87B941EFB1CB100269C2B /* STPSourceVerificationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPSourceVerificationTest.m; sourceTree = "<group>"; };
8BE5AE8A1EF8905B0081A33C /* STPCardParamsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPCardParamsTest.m; sourceTree = "<group>"; };
B318518220BE011700EE8C0F /* STPColorUtilsTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPColorUtilsTest.m; sourceTree = "<group>"; };
B32B175C20F6D2C4000D6EF8 /* STPGenericStripeObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = STPGenericStripeObject.h; sourceTree = "<group>"; };
B32B175D20F6D2C4000D6EF8 /* STPGenericStripeObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPGenericStripeObject.m; sourceTree = "<group>"; };
B32B176220F6D722000D6EF8 /* STPGenericStripeObjectTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPGenericStripeObjectTest.m; sourceTree = "<group>"; };
B3302F452006FBA7005DDBE9 /* STPConnectAccountParamsTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPConnectAccountParamsTest.m; sourceTree = "<group>"; };
B3302F4B200700AB005DDBE9 /* STPLegalEntityParamsTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPLegalEntityParamsTest.m; sourceTree = "<group>"; };
B347DD461FE35423006B3BAC /* STPValidatedTextField.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = STPValidatedTextField.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1645,6 +1653,7 @@
C1CFCB701ED5E11500BE45DF /* STPFileTest.m */,
04CDB51F1A5F3A9300B854EE /* STPFormEncoderTest.m */,
C16F66AA1CA21BAC006A21B5 /* STPFormTextFieldTest.m */,
B32B176220F6D722000D6EF8 /* STPGenericStripeObjectTest.m */,
04827D171D257A6C002DB3E8 /* STPImageLibraryTest.m */,
B3302F4B200700AB005DDBE9 /* STPLegalEntityParamsTest.m */,
045A62AA1B8E7259000165CE /* STPPaymentCardTextFieldTest.m */,
Expand Down Expand Up @@ -1900,6 +1909,8 @@
8B429ADD1EF9EFF600F95F34 /* STPFile+Private.h */,
04CDB4C41A5F30A700B854EE /* STPFormEncoder.h */,
04CDB4C51A5F30A700B854EE /* STPFormEncoder.m */,
B32B175C20F6D2C4000D6EF8 /* STPGenericStripeObject.h */,
B32B175D20F6D2C4000D6EF8 /* STPGenericStripeObject.m */,
C1CFCB661ED4E38900BE45DF /* STPInternalAPIResponseDecodable.h */,
F1D3A2471EB012010095BFA9 /* STPMultipartFormDataEncoder.h */,
F1D3A2481EB012010095BFA9 /* STPMultipartFormDataEncoder.m */,
Expand Down Expand Up @@ -2187,6 +2198,7 @@
0438EF491B74183100D506CC /* STPCardBrand.h in Headers */,
F12C8DC21D63DE9F00ADA0D7 /* STPPaymentContextAmountModel.h in Headers */,
F1D96F971DC7D82400477E64 /* STPLocalizationUtils.h in Headers */,
B32B175F20F6D2C4000D6EF8 /* STPGenericStripeObject.h in Headers */,
049A3FA91CC96B3B00F57DE7 /* STPBackendAPIAdapter.h in Headers */,
049952D61BCF14930088C703 /* STPAPIRequest.h in Headers */,
04827D111D2575C6002DB3E8 /* STPImageLibrary.h in Headers */,
Expand Down Expand Up @@ -2330,6 +2342,7 @@
F12829DA1D7747E4008B10D6 /* STPBundleLocator.h in Headers */,
C11810951CC6C4700022FB55 /* PKPaymentAuthorizationViewController+Stripe_Blocks.h in Headers */,
04CDB5161A5F30A700B854EE /* StripeError.h in Headers */,
B32B175E20F6D2C4000D6EF8 /* STPGenericStripeObject.h in Headers */,
049A3F991CC76A2400F57DE7 /* NSBundle+Stripe_AppName.h in Headers */,
04E32A9D1B7A9490009C9E35 /* STPPaymentCardTextField.h in Headers */,
C1BD9B221E393FFE00CEE925 /* STPSourceReceiver.h in Headers */,
Expand Down Expand Up @@ -2843,6 +2856,7 @@
C11810991CC6D46D0022FB55 /* NSDecimalNumber+StripeTest.m in Sources */,
8B5B4B441EFDD925005CF475 /* STPSourceOwnerTest.m in Sources */,
8B82C5CA1F2BC78F009639F7 /* STPApplePayPaymentMethodTest.m in Sources */,
B32B176320F6D722000D6EF8 /* STPGenericStripeObjectTest.m in Sources */,
B3BDCACF20EEF4640034F7F5 /* STPPaymentIntentFunctionalTest.m in Sources */,
8B013C891F1E784A00DD831B /* STPPaymentConfigurationTest.m in Sources */,
C1EEDCC81CA2172700A54582 /* NSString+StripeTest.m in Sources */,
Expand Down Expand Up @@ -2935,6 +2949,7 @@
B3A2413C1FFEB57400A2F00D /* STPConnectAccountParams.m in Sources */,
C1BD9B2B1E39406C00CEE925 /* STPSourceOwner.m in Sources */,
C1BD9B311E3940A200CEE925 /* STPSourceRedirect.m in Sources */,
B32B176120F6D2C4000D6EF8 /* STPGenericStripeObject.m in Sources */,
04B31DE91D09D25F00EF1631 /* STPPaymentMethodsInternalViewController.m in Sources */,
F12C8DC51D63DE9F00ADA0D7 /* STPPaymentContextAmountModel.m in Sources */,
04633B011CD129CB009D4FB5 /* STPPhoneNumberValidator.m in Sources */,
Expand Down Expand Up @@ -3001,6 +3016,7 @@
0438EF2F1B7416BB00D506CC /* STPFormTextField.m in Sources */,
045D71101CEEE30500F6CD65 /* STPAspects.m in Sources */,
F152321D1EA92FC100D65C67 /* STPRedirectContext.m in Sources */,
B32B176020F6D2C4000D6EF8 /* STPGenericStripeObject.m in Sources */,
04B31E011D131D9000EF1631 /* STPPaymentCardTextFieldCell.m in Sources */,
04633B0D1CD44F6C009D4FB5 /* PKPayment+Stripe.m in Sources */,
F1852F951D80B6EC00367C86 /* STPStringUtils.m in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion Stripe/STPAPIClient+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ toCustomerUsingKey:(STPEphemeralKey *)ephemeralKey
*/
+ (void)deleteSource:(NSString *)sourceID
fromCustomerUsingKey:(STPEphemeralKey *)ephemeralKey
completion:(STPSourceProtocolCompletionBlock)completion;
completion:(STPErrorBlock)completion;

@end

Expand Down
13 changes: 7 additions & 6 deletions Stripe/STPAPIClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@

#import "NSBundle+Stripe_AppName.h"
#import "NSError+Stripe.h"
#import "STPAPIRequest.h"
#import "NSMutableURLRequest+Stripe.h"
#import "STPAnalyticsClient.h"
#import "STPAPIRequest.h"
#import "STPBankAccount.h"
#import "STPCard.h"
#import "STPDispatchFunctions.h"
#import "STPEphemeralKey.h"
#import "STPFormEncoder.h"
#import "STPGenericStripeObject.h"
#import "STPMultipartFormDataEncoder.h"
#import "STPMultipartFormDataPart.h"
#import "NSMutableURLRequest+Stripe.h"
#import "STPPaymentConfiguration.h"
#import "STPPaymentIntent+Private.h"
#import "STPPaymentIntentParams.h"
Expand Down Expand Up @@ -542,15 +543,15 @@ + (void)addSource:(NSString *)sourceID
}];
}

+ (void)deleteSource:(NSString *)sourceID fromCustomerUsingKey:(STPEphemeralKey *)ephemeralKey completion:(STPSourceProtocolCompletionBlock)completion {
+ (void)deleteSource:(NSString *)sourceID fromCustomerUsingKey:(STPEphemeralKey *)ephemeralKey completion:(STPErrorBlock)completion {
STPAPIClient *client = [self apiClientWithEphemeralKey:ephemeralKey];
NSString *endpoint = [NSString stringWithFormat:@"%@/%@/%@/%@", APIEndpointCustomers, ephemeralKey.customerID, APIEndpointSources, sourceID];
[STPAPIRequest<STPSourceProtocol> deleteWithAPIClient:client
endpoint:endpoint
parameters:nil
deserializers:@[[STPCard new], [STPSource new]]
completion:^(id object, __unused NSHTTPURLResponse *response, NSError *error) {
completion(object, error);
deserializers:@[[STPGenericStripeObject new]]
completion:^(__unused STPGenericStripeObject *object, __unused NSHTTPURLResponse *response, NSError *error) {
completion(error);
}];
}

Expand Down
2 changes: 1 addition & 1 deletion Stripe/STPCustomerContext.m
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ - (void)detachSourceFromCustomer:(id<STPSourceProtocol>)source completion:(STPEr

[STPAPIClient deleteSource:source.stripeID
fromCustomerUsingKey:ephemeralKey
completion:^(__unused id<STPSourceProtocol> obj, NSError *error) {
completion:^(NSError *error) {
[self clearCachedCustomer];

if (completion) {
Expand Down
37 changes: 37 additions & 0 deletions Stripe/STPGenericStripeObject.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// STPGenericStripeObject.h
// Stripe
//
// Created by Daniel Jackson on 7/11/18.
// Copyright © 2018 Stripe, Inc. All rights reserved.
//

#import <Foundation/Foundation.h>

#import "STPAPIResponseDecodable.h"
#import "STPSourceProtocol.h"

NS_ASSUME_NONNULL_BEGIN

/**
Generic decodable Stripe object. It only has an `id`

`STPAPIRequest` expects to be able to parse an object out of the result, otherwise
it considers the request to have failed.
This primarily exists to handle the response to calls like these:
- https://stripe.com/docs/api#delete_card + https://stripe.com/docs/api#detach_source
- https://stripe.com/docs/api#customer_delete_bank_account

This will probably never be useful to expose publicly, the caller probably already has the
id.
*/
@interface STPGenericStripeObject : NSObject <STPAPIResponseDecodable>

/**
The stripe id of this object.
*/
@property (nonatomic, readonly) NSString *stripeId;

@end

NS_ASSUME_NONNULL_END
36 changes: 36 additions & 0 deletions Stripe/STPGenericStripeObject.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// STPGenericStripeObject.m
// Stripe
//
// Created by Daniel Jackson on 7/11/18.
// Copyright © 2018 Stripe, Inc. All rights reserved.
//

#import "STPGenericStripeObject.h"

#import "NSDictionary+Stripe.h"

@interface STPGenericStripeObject ()
@property (nonatomic, copy, readwrite) NSString *stripeId;
@property (nonatomic, copy, readwrite) NSDictionary *allResponseFields;
@end

@implementation STPGenericStripeObject

+ (nullable instancetype)decodedObjectFromAPIResponse:(nullable NSDictionary *)response {
NSDictionary *dict = [response stp_dictionaryByRemovingNulls];
NSString *stripeId = [dict stp_stringForKey:@"id"];

// required fields
if (!stripeId) {
return nil;
}
STPGenericStripeObject *source = [self new];

source.stripeId = response[@"id"];
source.allResponseFields = dict;

return source;
}

@end
4 changes: 2 additions & 2 deletions Tests/Tests/STPCustomerContextTest.m
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,9 @@ - (void)testDetachSourceFromCustomerCallsAPIClientCorrectly {
fromCustomerUsingKey:[OCMArg isEqual:customerKey]
completion:[OCMArg any]])
.andDo(^(NSInvocation *invocation) {
STPCustomerCompletionBlock completion;
STPErrorBlock completion;
[invocation getArgument:&completion atIndex:4];
completion([STPFixtures customerWithSingleCardTokenSource], nil);
completion(nil);
[exp fulfill];
});
id mockKeyManager = [self mockKeyManagerWithKey:customerKey];
Expand Down
27 changes: 27 additions & 0 deletions Tests/Tests/STPGenericStripeObjectTest.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// STPGenericStripeObjectTest.m
// StripeiOS Tests
//
// Created by Daniel Jackson on 7/11/18.
// Copyright © 2018 Stripe, Inc. All rights reserved.
//

#import <XCTest/XCTest.h>

#import "STPGenericStripeObject.h"

@interface STPGenericStripeObjectTest : XCTestCase

@end

@implementation STPGenericStripeObjectTest

- (void)testDecodedObject {
XCTAssertNil([STPGenericStripeObject decodedObjectFromAPIResponse:@{}]);

STPGenericStripeObject *obj = [STPGenericStripeObject decodedObjectFromAPIResponse:@{@"id": @"card_XYZ"}];
XCTAssertNotNil(obj);
XCTAssertEqualObjects(obj.stripeId, @"card_XYZ");
}

@end