- Upgrade to 1.0

This commit is contained in:
giuseppenuc committed 2016-12-28 18:49:02 +01:00
1 parent 4e66c377fd
commit 0c2b3f1c25
452 files changed
+33888 -16806

No files matched your search

View File
Whitespace-only changes.
View File
Whitespace-only changes.
+51
View File
@@ -0,0 +1,51 @@
//
// PNAddress.h
// Pods
//
// Created by Giuseppe Nucifora on 13/01/16.
//
//
#import "PNObject.h"
#import "PNLocation.h"
@interface PNAddress : PNObject <PNObjectSubclassing>
///--------------------------------------
#pragma mark - PNAddress Properties
///--------------------------------------
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSString * country;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSString * province;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSString * city;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSString * street;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSNumber * number;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSString * zip;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSString * istruction;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) PNLocation * location;
@end
+37
View File
@@ -0,0 +1,37 @@
//
// PNAddress.m
// Pods
//
// Created by Giuseppe Nucifora on 13/01/16.
//
//
#import "PNAddress.h"
@implementation PNAddress
+ (NSString *) objectClassName {
return @"PNAddress";
}
+ (NSString *)objectEndPoint {
return @"PNAddress";
}
+ (NSDictionary *) objcetMapping {
NSDictionary *mapping = @{@"country":@"country",
@"province":@"province",
@"city":@"city",
@"street":@"street",
@"number":@"number",
@"zip":@"zip",
@"location":@{PNObjectMappingKey:@"location",PNObjectMappingType:@"PNLocation"},
};
return mapping;
}
+ (BOOL)singleInstance {
return NO;
}
@end
+102
View File
@@ -0,0 +1,102 @@
//
// PNInstallation.h
// Pods
//
// Created by Giuseppe Nucifora on 27/01/16.
//
//
#import "PNObject.h"
#import "PNUser.h"
typedef NS_ENUM(NSInteger, PNInstallationStatus) {
PNInstallationStatusNew = 0,
PNInstallationStatusChange,
PNInstallationStatusNone,
};
@interface PNInstallation : PNObject
/**
Gets the currently-running installation from disk and returns an instance of it.
If this installation is not stored on disk, returns a `PFInstallation`
with `deviceType` and `installationId` fields set to those of the
current installation.
@result Returns a `Installation` that represents the currently-running installation.
*/
+ (instancetype _Nonnull)currentInstallation;
/**
* <#Description#>
*
* @param deviceTokenData <#deviceTokenData description#>
*
* @return RETURN YES if token is not set o token changes, NO if token is the same of old token.
*/
- (PNInstallationStatus) setDeviceTokenFromData:(nullable NSData *)deviceTokenData;
/**
* <#Description#>
*/
- (void) resetBadge;
- (void) setRegistered;
- (void) setUpdated;
///--------------------------------------
#pragma mark - PNInstallation Properties
///--------------------------------------
@property (nonatomic, strong, nullable) PNUser *user;
/**
* <#Description#>
*/
@property (nonatomic, strong, readonly, nonnull) NSString *deviceType;
/**
* <#Description#>
*/
@property (nonatomic, strong, readonly, nonnull) NSString *deviceModel;
/**
* <#Description#>
*/
@property (nonatomic, strong, readonly, nonnull) NSString *deviceName;
/**
* <#Description#>
*/
@property (nonatomic, strong, readonly, nonnull) NSString *osVersion;
/**
* <#Description#>
*/
@property (nonatomic, strong, readonly, nonnull) NSString *localeIdentifier;
/**
* <#Description#>
*/
@property (nonatomic, strong, readonly, nullable) NSString *deviceToken;
/**
* <#Description#>
*/
@property (nonatomic, strong, readonly, nullable) NSString *oldDeviceToken;
/**
* <#Description#>
*/
@property (nonatomic, assign) NSInteger badge;
/**
* <#Description#>
*/
@property (nonatomic, readonly) PNInstallationStatus installationStatus;
/**
* <#Description#>
*/
@property (nonatomic, strong, readonly, nullable) NSDate *registeredAt;
/**
* <#Description#>
*/
@property (nonatomic, strong, readonly, nullable) NSDate *updatedAt;
/**
* <#Description#>
*/
@property (nonatomic, strong, readonly, nullable) NSDate *lastTokenUpdate;
@end
+195
View File
@@ -0,0 +1,195 @@
//
// PNInstallation.m
// Pods
//
// Created by Giuseppe Nucifora on 27/01/16.
//
//
#import "PNInstallation.h"
#import "DJLocalization.h"
#import "PNObjectConfig.h"
@interface PNInstallation() <PNObjectSubclassing>
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSData *deviceTokenData;
@end
@implementation PNInstallation
static id INSTALLATION = nil;
static bool isFirstAccess = YES;
#pragma mark PNObjectSubclassing Protocol
+ (NSDictionary *)objcetMapping {
NSDictionary *mapping = @{@"user":@{PNObjectMappingKey:@"user",PNObjectMappingType:[[[PNObjectConfig sharedInstance] userSubClass] PNObjClassName]},
@"deviceType":@"deviceType",
@"deviceModel":@"deviceModel",
@"deviceName":@"deviceName",
@"osVersion":@"osVersion",
@"deviceToken":@"deviceToken",
@"oldDeviceToken":@"oldDeviceToken",
@"badge":@"badge",
@"localeIdentifier":@"localeIdentifier",
@"registeredAt":@"registeredAt",
@"updatedAt":@"updatedAt",
@"lastTokenUpdate":@"lastTokenUpdate",
};
return mapping;
}
+ (NSString *)objectClassName {
return @"PNInstallation";
}
+ (NSString *)objectEndPoint {
return @"PNInstallation";
}
+ (BOOL) singleInstance {
return YES;
}
#pragma mark -
#pragma mark Public Methods
+ (instancetype) currentInstallation {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
isFirstAccess = NO;
INSTALLATION = [[super allocWithZone:NULL] initForCurrentInstallation];
});
return INSTALLATION;
}
- (PNInstallationStatus) setDeviceTokenFromData:(NSData *)deviceTokenData {
if(!deviceTokenData){
_installationStatus = PNInstallationStatusNone;
return _installationStatus;
}
self.deviceTokenData = deviceTokenData;
NSString *ptoken = [[[[deviceTokenData description]
stringByReplacingOccurrencesOfString:@"<"withString:@""]
stringByReplacingOccurrencesOfString:@">" withString:@""]
stringByReplacingOccurrencesOfString: @" " withString: @""];
if (!_deviceToken) {
_installationStatus = PNInstallationStatusNew;
}
else if (_deviceToken && ![ptoken isEqualToString:_deviceToken]) {
_installationStatus = PNInstallationStatusChange;
}
/*[self setValue:_deviceToken forKey:VariableName(oldDeviceToken)];
[self setValue:ptoken forKey:VariableName(deviceToken)];
*/
_oldDeviceToken = _deviceToken;
_deviceToken = ptoken;
if (_installationStatus != PNInstallationStatusNone) {
_lastTokenUpdate = [NSDate date];
}
return _installationStatus;
}
- (void) setBadge:(NSInteger)badge {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:badge];
}
- (NSInteger) badge {
return [[UIApplication sharedApplication] applicationIconBadgeNumber];
}
- (void) resetBadge {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
}
- (void) setRegistered {
_registeredAt = [NSDate date];
}
- (void) setUpdated {
_updatedAt = [NSDate date];
}
- (void) setUser:(PNUser *)user {
if (!_user && user) {
_user = user;
[[NSNotificationCenter defaultCenter] postNotificationName:PNObjectLocalNotificationPNInstallationUserNew object:nil];
}
else if(_user.objID != user.objID) {
_user = user;
[[NSNotificationCenter defaultCenter] postNotificationName:PNObjectLocalNotificationPNInstallationUserChange object:nil];
}
else if (user == nil && _user){
_user = nil;
[[NSNotificationCenter defaultCenter] postNotificationName:PNObjectLocalNotificationPNInstallationUserDelete object:nil];
}
}
#pragma mark -
#pragma mark Private Methods
- (id) initForCurrentInstallation
{
if(INSTALLATION){
return INSTALLATION;
}
if (isFirstAccess) {
[self doesNotRecognizeSelector:_cmd];
}
NSDictionary *savedInstallation = [[PNObjectModel sharedInstance] fetchObjectsWithClass:[self class]];
if (savedInstallation) {
Class objectClass = NSClassFromString([[self class] PNObjClassName]);
self = [[objectClass alloc] initWithLocalJSON:savedInstallation];
}
else {
self = [super init];
}
if (self) {
/*[super setValue:@"iOS" forKey:VariableName(deviceType)];
[super setValue:[[UIDevice currentDevice] model] forKey:VariableName(deviceModel)];
[super setValue:[[UIDevice currentDevice] systemVersion] forKey:VariableName(osVersion)];
[self setValue:[[UIDevice currentDevice] name] forKey:VariableName(deviceName)];
[self setValue:[[DJLocalizationSystem shared] language] forKey:VariableName(localeIdentifier)];
*/
_installationStatus = PNInstallationStatusNone;
_deviceType = @"iOS";
_deviceModel = [[UIDevice currentDevice] model];
_osVersion = [[UIDevice currentDevice] systemVersion];
_deviceName = [[UIDevice currentDevice] name];
_localeIdentifier = [[DJLocalizationSystem shared] language];
}
return self;
}
#pragma mark -
@end
+26
View File
@@ -0,0 +1,26 @@
//
// PNLocation.h
// Pods
//
// Created by Giuseppe Nucifora on 13/01/16.
//
//
#import "PNObject.h"
@interface PNLocation : PNObject <PNObjectSubclassing>
///--------------------------------------
#pragma mark - PNLocation Properties
///--------------------------------------
/**
* <#Description#>
*/
@property (nonatomic) CGFloat lat;
/**
* <#Description#>
*/
@property (nonatomic) CGFloat lng;
@end
+32
View File
@@ -0,0 +1,32 @@
//
// PNLocation.m
// Pods
//
// Created by Giuseppe Nucifora on 13/01/16.
//
//
#import "PNLocation.h"
@implementation PNLocation
+ (NSString *) objectClassName {
return @"PNLocation";
}
+(NSString *)objectEndPoint {
return @"PNLocation";
}
+ (NSDictionary *) objcetMapping {
NSDictionary *mapping = @{@"lat":@"lat",
@"lng":@"lng",
};
return mapping;
}
+ (BOOL)singleInstance {
return NO;
}
@end
@@ -0,0 +1,30 @@
//
// PNObjcPassword.h
// Pods
//
// Created by Giuseppe Nucifora on 13/01/16.
//
//
#import "PNObject.h"
@interface PNObjcPassword : PNObject <PNObjectSubclassing>
+ (BOOL) validateMinimumRequirenment:(NSString * _Nullable) passString;
- (BOOL) isValid;
///--------------------------------------
#pragma mark - PNObjcPassword Properties
///--------------------------------------
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSString *password;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSString *confirmPassword;
@end
@@ -0,0 +1,81 @@
//
// PNObjcPassword.m
// Pods
//
// Created by Giuseppe Nucifora on 13/01/16.
//
//
#import "PNObjcPassword.h"
#import "PNUser.h"
#import "PNObjectConstants.h"
@implementation PNObjcPassword
+ (NSString *) objectClassName {
return @"PNObjcPassword";
}
+(NSString *)objectEndPoint {
return @"PNObjcPassword";
}
+ (NSDictionary *) objcetMapping {
NSDictionary *mapping = @{@"password":@"password",
@"confirmPassword":@"confirmPassword",
};
return mapping;
}
+ (BOOL)singleInstance {
return NO;
}
- (void) setPassword:(NSString *)password {
if ([self validateMinimumRequirenment:password]) {
_password = password;
}
else {
NSLogDebug(@"Inserted Passord is not valid.Lenght must be >= %ld",(long)[[PNObjectConfig sharedInstance] minPasswordLenght]);
}
}
- (void) setConfirmPassword:(NSString *)confirmPassword {
if ([self validateMinimumRequirenment:confirmPassword]) {
if ([confirmPassword isEqualToString:_password]) {
_confirmPassword = confirmPassword;
}
else {
NSLogDebug(@"Inserted Passord is not same password.");
}
}
else {
NSLogDebug(@"Inserted Passord is not valid.Lenght must be >= %ld",(long)[[PNObjectConfig sharedInstance] minPasswordLenght]);
}
}
- (BOOL)isValid {
if ([self validateMinimumRequirenment:_password] && [self validateMinimumRequirenment:_confirmPassword] && [_confirmPassword isEqualToString:_password]) {
return YES;
}
return NO;
}
- (BOOL) validateMinimumRequirenment:(NSString * _Nullable) passString {
if ([passString length] >= [[PNObjectConfig sharedInstance] minPasswordLenght]) {
return YES;
}
return NO;
}
+ (BOOL) validateMinimumRequirenment:(NSString * _Nullable) passString {
if ([passString length] >= [[PNObjectConfig sharedInstance] minPasswordLenght]) {
return YES;
}
return NO;
}
@end
+225
View File
@@ -0,0 +1,225 @@
//
// PNUser.h
// Pods
//
// Created by Giuseppe Nucifora on 15/01/16.
//
//
#import "PNObject.h"
#import "PNObjcPassword.h"
@interface PNUser : PNObject
/**
* gets singleton object of current user session.
*
* @return singleton
*/
+ (instancetype _Nonnull) currentUser;
/**
* reset current user and gets new singleton object of current user session.
*
* @return <#return value description#>
*/
+ (instancetype _Nonnull) resetUser;
/**
* <#Description#>
*
* @param password <#password description#>
*
* @return <#return value description#>
*/
+ (BOOL) isValidPassword:(NSString* _Nonnull) password;
/**
* <#Description#>
*/
- (void) logout;
/**
* <#Description#>
*
* @return <#return value description#>
*/
- (BOOL) hasValidEmailAndPasswordData;
/**
* <#Description#>
*
* @param email <#email description#>
* @param password <#password description#>
* @param success <#success description#>
* @param failure <#failure description#>
*/
+ (void) loginCurrentUserWithEmail:(NSString * _Nonnull) email
password:(NSString * _Nonnull) password
withBlockSuccess:(nullable void (^)(PNUser * _Nullable responseObject))success
failure:(nullable void (^)(NSError * _Nonnull error))failure;
/**
* <#Description#>
*
* @param success <#success description#>
* @param failure <#failure description#>
*/
- (void) registerWithBlockProgress:(nullable void (^)(NSProgress * _Nonnull uploadProgress)) uploadProgress
Success:(nullable void (^)(PNUser * _Nullable responseObject))success
failure:(nullable void (^)(NSError * _Nonnull error))failure;
/**
* <#Description#>
*
* @param viewController <#viewController description#>
* @param success <#success description#>
* @param failure <#failure description#>
*/
+ (void) socialLoginFromViewController:(UIViewController* _Nullable) viewController
blockSuccess:(nullable void (^)(PNUser * _Nullable responseObject))success
failure:(nullable void (^)(NSError * _Nonnull error))failure;
+ (void) socialLoginWithBlockSuccess:(nullable void (^)(PNUser * _Nullable responseObject))success
failure:(nullable void (^)(NSError * _Nonnull error))failure;
+ (void) socialUserFromViewController:(UIViewController* _Nullable) viewController
blockSuccess:(nullable void (^)(PNUser * _Nullable responseObject))success
failure:(nullable void (^)(NSError * _Nonnull error))failure;
/**
* <#Description#>
*
* @param avatar <#avatar description#>
* @param uploadProgress <#uploadProgress description#>
* @param success <#success description#>
* @param failure <#failure description#>
*/
+ (void) uploadAvatar:(UIImage * _Nonnull) avatar
Progress:(nullable void (^)(NSProgress * _Nonnull uploadProgress)) uploadProgress
Success:(nullable void (^)(NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSError * _Nonnull error))failure;
/**
* <#Description#>
*/
- (void) reloadFormServer;
/**
* <#Description#>
*
* @param success <#success description#>
* @param failure <#failure description#>
*/
- (void) reloadFormServerWithBlockSuccess:(nullable void (^)(PNUser * _Nullable currentUser))success
failure:(nullable void (^)(NSError * _Nonnull error))failure;
/**
* <#Description#>
*
* @return <#return value description#>
*/
- (BOOL) isAuthenticated;
- (UIImage* _Nonnull) userProfileImage;
- (UIImage* _Nonnull) userProfileImage:(BOOL) forceReload;
- (BOOL) isFacebookUser;
//- (void) setPassword:(NSString * _Nonnull)password inBackGroundWithBlock:(nullable void (^)(BOOL saveStatus, id responseObject, NSError * error)) responseBlock;
///--------------------------------------
#pragma mark - PNUser Properties
///--------------------------------------
/**
* <#Description#>
*/
@property (strong, nonatomic, nullable) NSString * userId;
/**
* <#Description#>
*/
@property (strong, nonatomic, nullable) NSString * firstName;
/**
* <#Description#>
*/
@property (strong, nonatomic, nullable) NSString * lastName;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSURL * profileImageUrl;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) UIImage * profileImage;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSString * sex;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSDate * birthDate;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSString * phone;
/**
* <#Description#>
*/
@property (nonatomic) BOOL hasAcceptedPrivacy;
/**
* <#Description#>
*/
@property (nonatomic) BOOL hasAcceptedNewsletter;
/**
* <#Description#>
*/
@property (nonatomic) BOOL hasVerifiedEmail;
/**
* <#Description#>
*/
@property (nonatomic) BOOL hasVerifiedPhone;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSDate * emailVerifiedDate;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSString * email;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSString * username;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) PNObjcPassword * password;
/**
* <#Description#>
*/
@property (nonatomic) BOOL publicProfile;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSNumber * loginCount;
@property (nonatomic) BOOL facebookUser;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSString * facebookId;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSString * facebookAccessToken;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSDate * registeredAt;
@end
+525
View File
@@ -0,0 +1,525 @@
//
// PNUser.m
// Pods
//
// Created by Giuseppe Nucifora on 15/01/16.
//
//
#import "PNUser.h"
#import "NSString+Helper.h"
#import "PNObjectConstants.h"
#import "PNObject+Protected.h"
#import "PNObject+PNObjectConnection.h"
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <FBSDKLoginKit/FBSDKLoginKit.h>
#import <FBSDKShareKit/FBSDKShareKit.h>
#import "PNObjcPassword.h"
#import "HTTPStatusCodes.h"
@interface PNUser() <PNObjectSubclassing>
@property (nonatomic) BOOL authenticated;
@end
@implementation PNUser
@synthesize password = _password;
static id USER = nil;
static bool isFirstAccess = YES;
#pragma mark - Public Method
+ (instancetype) currentUser {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
isFirstAccess = NO;
USER = [[super allocWithZone:NULL] initForCurrentUser];
});
return USER;
}
+ (instancetype)resetUser {
[USER autoRemoveLocally];
USER = nil;
return [self currentUser];
}
#pragma mark - Life Cycle
- (instancetype)copy
{
Class objectClass = NSClassFromString([[self class] PNObjClassName]);
return [[objectClass alloc] init];
}
- (instancetype)mutableCopy
{
Class objectClass = NSClassFromString([[self class] PNObjClassName]);
return [[objectClass alloc] init];
}
- (instancetype) initForCurrentUser
{
if(USER){
return USER;
}
if (isFirstAccess) {
[self doesNotRecognizeSelector:_cmd];
}
NSDictionary *savedUser = [[PNObjectModel sharedInstance] fetchObjectsWithClass:[self class]];
Class objectClass = NSClassFromString([[self class] PNObjClassName]);
if (savedUser) {
self = [[objectClass alloc] initWithLocalJSON:savedUser];
}
else {
self = [[objectClass alloc] init];
}
if (self) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[self autoLogin];
});
}
return self;
}
- (void) setEmail:(NSString *)email {
if ([email isValidEmail]) {
_email = email;
}
else {
NSLogDebug(@"insertedEmail is not valid.");
}
}
- (void)logout {
[[NSNotificationCenter defaultCenter] postNotificationName:PNObjectLocalNotificationUserWillLogout object:nil];
[self autoRemoveLocally];
[self resetObject];
[[NSNotificationCenter defaultCenter] postNotificationName:PNObjectLocalNotificationUserEndLogout object:nil];
}
- (BOOL) hasValidEmailAndPasswordData {
if(self.email && [self.email isValidEmail] && self.password && [self.password isValid]){
return YES;
}
return NO;
}
+ (BOOL) isValidPassword:(NSString* _Nonnull) password {
return [PNObjcPassword validateMinimumRequirenment:password];
}
- (void) autoLogin {
[self autoLoginWithBlockSuccess:nil failure:nil];
}
- (void) autoLoginWithBlockSuccess:(nullable void (^)(BOOL loginSuccess))success
failure:(nullable void (^)(NSError * _Nonnull error))failure {
[[PNObjectConfig sharedInstance] refreshTokenForUserWithBlockSuccess:^(BOOL refreshSuccess) {
if (success) {
success(refreshSuccess);
}
} failure:^(NSError * _Nonnull error) {
if (failure) {
failure(error);
}
}];
}
- (void) reloadFormServer {
[self reloadFormServerWithBlockSuccess:nil failure:nil];
}
- (void) reloadFormServerWithBlockSuccess:(nullable void (^)(PNUser * _Nullable currentUser))success
failure:(nullable void (^)(NSError * _Nonnull error))failure {
[self autoLoginWithBlockSuccess:^(BOOL loginSuccess) {
[[self class] GETWithEndpointAction:@"user/profile"
progress:nil
success:^(NSURLSessionDataTask * _Nullable task, id _Nullable responseObject) {
NSLogDebug(@"%@",[responseObject objectForKey:@"user"]);
[[[self class] currentUser] populateObjectFromJSON:[responseObject objectForKey:@"user"]];
[[[self class] currentUser] updateFacebookData];
[[[self class] currentUser] saveLocally];
[[NSNotificationCenter defaultCenter] postNotificationName:PNObjectLocalNotificationUserReloadFromServerSuccess object:nil];
if (success) {
success([[self class] currentUser]);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLogDebug(@"%@",error);
if (failure) {
failure(error);
}
}];
} failure:^(NSError * _Nonnull error) {
NSLogDebug(@"error : %@",error);
if (failure) {
failure(error);
}
}];
}
- (void) registerWithBlockProgress:(nullable void (^)(NSProgress * _Nonnull uploadProgress)) uploadProgress
Success:(nullable void (^)(PNUser * _Nullable responseObject))success
failure:(nullable void (^)(NSError * _Nonnull error))failure {
[[self class] POSTWithEndpointAction:@"registration/register" parameters:[self JSONFormObject]
progress:uploadProgress
success:^(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject) {
NSLog(@"response %@",responseObject);
if(success){
[[[self class] currentUser] saveLocally];
success([[self class] currentUser]);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLogDebug(@"error : %ld",(long)[error code]);
if (failure) {
failure(error);
}
}];
}
+ (void) socialLoginFromViewController:(UIViewController* _Nullable) viewController
blockSuccess:(nullable void (^)(PNUser * _Nullable responseObject))success
failure:(nullable void (^)(NSError * _Nonnull error))failure {
if (!viewController) {
viewController = [PNObjectUtilities topViewController];
}
if ([FBSDKAccessToken currentAccessToken]) {
//FBSDKProfile *user = [FBSDKProfile currentProfile];
[FBSDKAccessToken refreshCurrentAccessToken:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
if (error) {
if (failure) {
failure(error);
}
}
else {
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:@"me" parameters:@{@"fields": @"first_name, last_name, link, birthday, email, gender"}];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
NSLogDebug(@"%@",result);
NSLogDebug(@"%@",error);
if (error) {
if (failure) {
failure(error);
}
}
else {
[[PNObjectConfig sharedInstance] refreshTokenForUserWithFacebookID:[result objectForKey:@"id"] facebookToken:[FBSDKAccessToken currentAccessToken].tokenString withBlockSuccess:^(BOOL refreshSuccess) {
PNUser *user = [[self class] new];
[user setFacebookId:[result objectForKey:@"id"]];
[user setAuthenticated:YES];
[user setFacebookUser:YES];
[user saveLocally];
[user reloadFormServer];
USER = user;
if (success) {
success(user);
}
} failure:^(NSError * _Nonnull error) {
if (failure) {
failure(error);
}
}];
}
}];
}
}];
}
else {
FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
[login logInWithReadPermissions: @[@"public_profile",@"email",@"user_birthday"] fromViewController:viewController handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
if (error) {
NSLog(@"Process error");
if (failure) {
failure(error);
}
} else if (result.isCancelled) {
NSLog(@"Cancelled");
if (failure) {
NSError *error = [NSError errorWithDomain:NSLocalizedString(@"Request cancelled", @"") code:kHTTPStatusCodeMethodNotAllowed userInfo:nil];
failure(error);
}
} else {
NSLog(@"Logged in");
[self socialLoginFromViewController:viewController blockSuccess:success failure:failure];
}
}];
}
}
+ (void) socialUserFromViewController:(UIViewController* _Nullable) viewController
blockSuccess:(nullable void (^)(PNUser * _Nullable responseObject))success
failure:(nullable void (^)(NSError * _Nonnull error))failure {
if (!viewController) {
viewController = [PNObjectUtilities topViewController];
}
if ([FBSDKAccessToken currentAccessToken]) {
//FBSDKProfile *user = [FBSDKProfile currentProfile];
[FBSDKAccessToken refreshCurrentAccessToken:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
if (error) {
if (failure) {
failure(error);
}
}
else {
FBSDKGraphRequest *request = [[FBSDKGraphRequest alloc] initWithGraphPath:@"me" parameters:@{@"fields": @"first_name, last_name, link, birthday, email, gender"}];
[request startWithCompletionHandler:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
NSLogDebug(@"%@",result);
NSLogDebug(@"%@",error);
if (error) {
if (failure) {
failure(error);
}
}
else {
[[PNObjectConfig sharedInstance] refreshTokenForUserWithFacebookID:[result objectForKey:@"id"] facebookToken:[FBSDKAccessToken currentAccessToken].tokenString withBlockSuccess:^(BOOL refreshSuccess) {
PNUser *user = [[self class] new];
[user setFacebookId:[result objectForKey:@"id"]];
[user setAuthenticated:YES];
[user setFacebookUser:YES];
[user saveLocally];
[user reloadFormServer];
USER = user;
if (success) {
success(user);
}
} failure:^(NSError * _Nonnull error) {
if (failure) {
failure(error);
}
}];
}
}];
}
}];
}
else {
FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
[login logInWithReadPermissions: @[@"public_profile",@"email",@"user_birthday"] fromViewController:viewController handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
if (error) {
NSLog(@"Process error");
if (failure) {
failure(error);
}
} else if (result.isCancelled) {
NSLog(@"Cancelled");
if (failure) {
NSError *error = [NSError errorWithDomain:NSLocalizedString(@"Request cancelled", @"") code:kHTTPStatusCodeMethodNotAllowed userInfo:nil];
failure(error);
}
} else {
NSLog(@"Logged in");
[self socialUserFromViewController:viewController blockSuccess:success failure:failure];
}
}];
}
}
+ (void) socialLoginWithBlockSuccess:(nullable void (^)(PNUser * _Nullable responseObject))success
failure:(nullable void (^)(NSError * _Nonnull error))failure {
[self socialLoginFromViewController:nil blockSuccess:success failure:failure];
}
+ (void) loginCurrentUserWithEmail:(NSString * _Nonnull) email
password:(NSString * _Nonnull) password
withBlockSuccess:(nullable void (^)(PNUser * _Nullable responseObject))success
failure:(nullable void (^)(NSError * _Nonnull error))failure {
[[PNObjectConfig sharedInstance] refreshTokenForUserWithEmail:email password:password withBlockSuccess:^(BOOL refreshSuccess) {
if (refreshSuccess) {
PNUser *user = [[self class] new];
PNObjcPassword *objectPassword = [PNObjcPassword new];
[objectPassword setPassword:password];
[objectPassword setConfirmPassword:password];
[user setAuthenticated:YES];
[user setEmail:email];
[user setPassword:objectPassword];
[user saveLocally];
[user reloadFormServer];
USER = user;
if (success) {
success(user);
}
}
} failure:failure];
}
+ (void) uploadAvatar:(UIImage * _Nonnull) avatar
Progress:(nullable void (^)(NSProgress * _Nonnull uploadProgress)) uploadProgress
Success:(nullable void (^)(NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSError * _Nonnull error))failure {
PNObjectFormData *formData = [PNObjectFormData formDataFromUIImage:avatar compression:1 name:@"file" fileName:@"avatar.jpg" mimeType:@"image/jpeg"];
[self POSTWithEndpointAction:@"user/avatar"
formData:@[formData]
parameters:nil
progress:uploadProgress
success:^(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject) {
if (success) {
success(responseObject);
}
[[self currentUser] setProfileImage:avatar];
[[self currentUser] reloadFormServer];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (failure) {
failure(error);
}
}];
}
- (BOOL) isAuthenticated {
return self.authenticated;
}
- (BOOL) isFacebookUser {
[self updateFacebookData];
return self.facebookUser;
}
- (void) updateFacebookData {
if (self.facebookId || self.facebookAccessToken) {
self.facebookUser = YES;
}
else {
self.facebookUser = NO;
}
}
- (UIImage* _Nonnull) userProfileImage {
return [self userProfileImage:NO];
}
- (UIImage* _Nonnull) userProfileImage:(BOOL) forceReload {
if (!_profileImage || forceReload) {
if (_profileImageUrl) {
NSError* error = nil;
NSData* data = [NSData dataWithContentsOfURL:_profileImageUrl options:NSDataReadingUncached error:&error];
if (error) {
NSLog(@"%@", [error localizedDescription]);
return [UIImage imageNamed:@"userProfileAvatar"];
} else {
NSLog(@"Data has loaded successfully.");
return [UIImage imageWithData:data];
}
}
else {
return [UIImage imageNamed:@"userProfileAvatar"];
}
}
else {
return _profileImage;
}
}
#pragma mark PNObjectSubclassing Protocol
+ (NSDictionary *)objcetMapping {
NSDictionary *mapping = @{
@"userId":@"uuid",
@"firstName":@"firstName",
@"lastName":@"lastName",
@"profileImageUrl":@"profileImage",
@"sex":@"sex",
@"birthDate":@"birthDate",
@"phone":@"phone",
@"password":@{PNObjectMappingKey:@"password",PNObjectMappingType:[PNObjcPassword PNObjClassName]},
@"hasAcceptedPrivacy":@"hasAcceptedPrivacy",
@"hasAcceptedNewsletter":@"hasAcceptedNewsletter",
@"hasVerifiedEmail":@"hasVerifiedEmail",
@"hasVerifiedPhone":@"hasVerifiedPhone",
@"emailVerifiedDate":@"emailVerifiedDate",
@"email":@"email",
@"username":@"username",
@"publicProfile":@"publicProfile",
@"loginCount":@"loginCount",
@"facebookId":@"facebookId",
@"facebookAccessToken":@"facebookAccessToken",
@"isFacebookUser":@"isFacebookUser",
@"registeredAt":@"registeredAt",
@"authenticated":@"authenticated"
};
return mapping;
}
+ (NSString *)objectClassName {
return @"PNUser";
}
+ (NSString *) objectEndPoint {
return @"User";
}
+ (BOOL) singleInstance {
return YES;
}
#pragma mark -
@end
@@ -0,0 +1,76 @@
//
// PNObjectConnection.h
// Pods
//
// Created by Giuseppe Nucifora on 18/01/16.
//
//
#import "PNObject.h"
#import "PNObjectFormData.h"
@interface PNObject (PNObjectConnection)
+ (void) GETWithEndpointAction:(NSString * _Nonnull) endPoint
progress:(nullable void (^)(NSProgress * _Nullable downloadProgress)) downloadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure;
+ (void) GETWithEndpointAction:(NSString * _Nonnull) endPoint
parameters:(NSDictionary * _Nullable) parameters
progress:(nullable void (^)(NSProgress * _Nullable downloadProgress)) downloadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure;
+ (void) GETWithEndpointAction:(NSString * _Nonnull) endPoint
parameters:(NSDictionary * _Nullable) parameters
retries:(NSInteger) retries
progress:(nullable void (^)(NSProgress * _Nullable downloadProgress)) downloadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure;
+ (void) POSTWithEndpointAction:(NSString * _Nonnull) endPoint
parameters:(NSDictionary * _Nullable) parameters
progress:(nullable void (^)(NSProgress * _Nullable uploadProgress)) uploadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure;
+ (void) POSTWithEndpointAction:(NSString * _Nonnull) endPoint
parameters:(NSDictionary * _Nullable) parameters
retries:(NSInteger) retries
progress:(nullable void (^)(NSProgress * _Nonnull uploadProgress)) uploadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure;
+ (void) POSTWithEndpointAction:(NSString * _Nonnull) endPoint
formData:(NSArray * _Nullable) postFormData
parameters:(NSDictionary * _Nullable) parameters
progress:(nullable void (^)(NSProgress * _Nonnull uploadProgress)) uploadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure;
+ (void) POSTWithEndpointAction:(NSString * _Nonnull) endPoint
formData:(NSArray * _Nullable) postFormData
parameters:(NSDictionary * _Nullable) parameters
retries:(NSInteger) retries
progress:(nullable void (^)(NSProgress * _Nonnull uploadProgress)) uploadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure;
+ (void) DELETEWithEndpointAction:(NSString * _Nonnull) endPoint
parameters:(NSDictionary * _Nullable) parameters
progress:(nullable void (^)(NSProgress * _Nonnull uploadProgress)) uploadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure;
+ (void) DELETEWithEndpointAction:(NSString * _Nonnull) endPoint
parameters:(NSDictionary * _Nullable) parameters
retries:(NSInteger) retries
progress:(nullable void (^)(NSProgress * _Nonnull uploadProgress)) uploadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure;
+ (id _Nonnull) parseObjectFromResponse:(id _Nullable) response;
@end
@@ -0,0 +1,298 @@
//
// PNObjectConnection.m
// Pods
//
// Created by Giuseppe Nucifora on 18/01/16.
//
//
#import "PNObject+PNObjectConnection.h"
#import "PNObjectConstants.h"
#import <NSDate_Utils/NSDate+NSDate_Util.h>
#import "PNObjectConfig.h"
#import "PNObjectModel.h"
#import <AFNetworking/AFNetworking.h>
#import "PNObject+Protected.h"
#define MAX_RETRIES 3
@implementation PNObject (PNObjectConnection)
+ (void) GETWithEndpointAction:(NSString * _Nonnull) endPoint
progress:(nullable void (^)(NSProgress * _Nonnull downloadProgress)) downloadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure {
return [self GETWithEndpointAction:endPoint parameters:nil progress:downloadProgress success:success failure:failure];
}
+ (void) GETWithEndpointAction:(NSString * _Nonnull) endPoint
parameters:(NSDictionary * _Nullable) parameters
progress:(nullable void (^)(NSProgress * _Nullable downloadProgress)) downloadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure {
return [self GETWithEndpointAction:endPoint parameters:parameters retries:MAX_RETRIES progress:downloadProgress success:success failure:failure];
}
+ (void) GETWithEndpointAction:(NSString * _Nonnull) endPoint
parameters:(NSDictionary * _Nullable) parameters
retries:(NSInteger) retries
progress:(nullable void (^)(NSProgress * _Nullable downloadProgress)) downloadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure {
if ([[PNObjectConfig sharedInstance] currentOauthCredential] && ![[[PNObjectConfig sharedInstance] currentOauthCredential] isExpired]) {
[[[PNObjectConfig sharedInstance] manager] GET:[[[PNObjectConfig sharedInstance] baseUrl] stringByAppendingFormat:@"%@",endPoint] parameters:parameters progress:downloadProgress success:^(NSURLSessionDataTask *task, id responseObject) {
if (success) {
success(task,responseObject);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (retries > 0) {
[[PNObjectConfig sharedInstance] refreshTokenWithBlockSuccess:^(BOOL refreshSuccess) {
return [self GETWithEndpointAction:endPoint parameters:parameters retries:retries-1 progress:downloadProgress success:success failure:failure];
} failure:^(NSError * _Nonnull error) {
if (failure) {
failure(nil,error);
}
}];
return;
}else {
if (failure) {
failure(task,error);
}
}
}];
}
else {
[[PNObjectConfig sharedInstance] refreshTokenWithBlockSuccess:^(BOOL refreshSuccess) {
return [self GETWithEndpointAction:endPoint parameters:parameters retries:retries-1 progress:downloadProgress success:success failure:failure];
} failure:^(NSError * _Nonnull error) {
if (failure) {
failure(nil,error);
}
}];
}
}
+ (void) POSTWithEndpointAction:(NSString * _Nonnull) endPoint
parameters:(NSDictionary * _Nullable) parameters
progress:(nullable void (^)(NSProgress * _Nonnull uploadProgress)) uploadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure {
return [self POSTWithEndpointAction:endPoint parameters:parameters retries:MAX_RETRIES progress:uploadProgress success:success failure:failure];
}
+ (void) POSTWithEndpointAction:(NSString * _Nonnull) endPoint
parameters:(NSDictionary * _Nullable) parameters
retries:(NSInteger) retries
progress:(nullable void (^)(NSProgress * _Nonnull uploadProgress)) uploadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure {
if ([[PNObjectConfig sharedInstance] currentOauthCredential] && ![[[PNObjectConfig sharedInstance] currentOauthCredential] isExpired]) {
[[[PNObjectConfig sharedInstance] manager] POST:[[[PNObjectConfig sharedInstance] baseUrl] stringByAppendingFormat:@"%@",endPoint] parameters:parameters progress:uploadProgress success:^(NSURLSessionDataTask *task, id responseObject) {
if (success) {
success(task,responseObject);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (retries > 0) {
[[PNObjectConfig sharedInstance] refreshTokenWithBlockSuccess:^(BOOL refreshSuccess) {
return [self POSTWithEndpointAction:endPoint parameters:parameters retries:retries-1 progress:uploadProgress success:success failure:failure];
} failure:^(NSError * _Nonnull error) {
if (failure) {
failure(nil,error);
}
}];
}
else {
if (failure) {
failure(task, error);
}
}
}];
}
else {
[[PNObjectConfig sharedInstance] refreshTokenWithBlockSuccess:^(BOOL refreshSuccess) {
return [self POSTWithEndpointAction:endPoint parameters:parameters retries:retries-1 progress:uploadProgress success:success failure:failure];
} failure:^(NSError * _Nonnull error) {
if (failure) {
failure(nil,error);
}
}];
}
}
+ (void) POSTWithEndpointAction:(NSString * _Nonnull) endPoint
formData:(NSArray * _Nullable) postFormData
parameters:(NSDictionary * _Nullable) parameters
progress:(nullable void (^)(NSProgress * _Nonnull uploadProgress)) uploadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure {
return [self POSTWithEndpointAction:endPoint formData:postFormData parameters:parameters retries:MAX_RETRIES progress:uploadProgress success:success failure:failure];
}
+ (void) POSTWithEndpointAction:(NSString * _Nonnull) endPoint
formData:(NSArray * _Nullable) postFormData
parameters:(NSDictionary * _Nullable) parameters
retries:(NSInteger) retries
progress:(nullable void (^)(NSProgress * _Nonnull uploadProgress)) uploadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure {
if ([[PNObjectConfig sharedInstance] currentOauthCredential] && ![[[PNObjectConfig sharedInstance] currentOauthCredential] isExpired]) {
[[[PNObjectConfig sharedInstance] manager] POST:[[[PNObjectConfig sharedInstance] baseUrl] stringByAppendingFormat:@"%@",endPoint]
parameters:parameters
constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
if (postFormData) {
for (PNObjectFormData *postData in postFormData) {
[formData appendPartWithFileData:[postData formData] name:[postData name] fileName:[postData fileName] mimeType:[postData mimeType]];
}
}
}
progress:uploadProgress
success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
if (success) {
success(task,responseObject);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (retries > 0) {
[[PNObjectConfig sharedInstance] refreshTokenWithBlockSuccess:^(BOOL refreshSuccess) {
return [self POSTWithEndpointAction:endPoint formData:postFormData parameters:parameters retries:retries-1 progress:uploadProgress success:success failure:failure];
} failure:^(NSError * _Nonnull error) {
if (failure) {
failure(nil,error);
}
}];
}
else {
if (failure) {
failure(nil,error);
}
}
}];
}
else {
[[PNObjectConfig sharedInstance] refreshTokenWithBlockSuccess:^(BOOL refreshSuccess) {
return [self POSTWithEndpointAction:endPoint formData:postFormData parameters:parameters retries:retries-1 progress:uploadProgress success:success failure:failure];
} failure:^(NSError * _Nonnull error) {
if (failure) {
failure(nil,error);
}
}];
}
}
+ (void) DELETEWithEndpointAction:(NSString * _Nonnull) endPoint
parameters:(NSDictionary * _Nullable) parameters
progress:(nullable void (^)(NSProgress * _Nonnull uploadProgress)) uploadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure {
return [self DELETEWithEndpointAction:endPoint parameters:parameters retries:MAX_RETRIES progress:uploadProgress success:success failure:failure];
}
+ (void) DELETEWithEndpointAction:(NSString * _Nonnull) endPoint
parameters:(NSDictionary * _Nullable) parameters
retries:(NSInteger) retries
progress:(nullable void (^)(NSProgress * _Nonnull uploadProgress)) uploadProgress
success:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSDictionary * _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure {
if ([[PNObjectConfig sharedInstance] currentOauthCredential] && ![[[PNObjectConfig sharedInstance] currentOauthCredential] isExpired]) {
[[[PNObjectConfig sharedInstance] manager] DELETE:[[[PNObjectConfig sharedInstance] baseUrl] stringByAppendingFormat:@"%@",endPoint]
parameters:parameters
success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
if (success) {
success(task,responseObject);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (retries > 0) {
[[PNObjectConfig sharedInstance] refreshTokenWithBlockSuccess:^(BOOL refreshSuccess) {
[self DELETEWithEndpointAction:endPoint parameters:parameters retries:retries-1 progress:uploadProgress success:success failure:failure];
} failure:^(NSError * _Nonnull error) {
if (failure) {
failure(nil,error);
}
}];
}
else {
if (failure) {
failure(nil,error);
}
}
}];
}
else {
[[PNObjectConfig sharedInstance] refreshTokenWithBlockSuccess:^(BOOL refreshSuccess) {
[self DELETEWithEndpointAction:endPoint parameters:parameters retries:retries-1 progress:uploadProgress success:success failure:failure];
} failure:^(NSError * _Nonnull error) {
if (failure) {
failure(nil,error);
}
}];
}
}
#pragma mark Private Methods
+ (id _Nonnull) parseObjectFromResponse:(id _Nullable) response {
id PNObjectResponse;
if (response) {
if ([response isKindOfClass:[NSDictionary class]] && [[response allKeys] count] > 0) {
PNObjectResponse = [[[self class] alloc] initWithRemoteJSON:[response copy]];
}
else if ([response isKindOfClass:[NSArray class]] && [response count] > 0){
NSMutableArray * resposeArray = [[NSMutableArray alloc] init];
for (id singleObjectDict in response) {
if ([singleObjectDict isKindOfClass:[NSDictionary class]]) {
id singleObject = [[[self class] alloc] initWithRemoteJSON:singleObjectDict];
[resposeArray addObject:singleObject];
}
}
PNObjectResponse = resposeArray;
}
}
return PNObjectResponse;
}
+ (NSError* _Nonnull) getErrorFromTask:(NSURLSessionDataTask* _Nonnull) task andError:(NSError * _Nonnull) error {
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
NSData *errorData = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey];
NSDictionary *serializedData = [NSJSONSerialization JSONObjectWithData: errorData options:kNilOptions error:nil];
return [NSError errorWithDomain:[error domain] code:response.statusCode userInfo:serializedData];
}
#pragma mark -
@end
+84
View File
@@ -0,0 +1,84 @@
//
// PNObject+Protected.h
// Pods
//
// Created by Giuseppe Nucifora on 25/01/16.
//
//
#import "PNObject.h"
@interface PNObject (Protected)
/**
* <#Description#>
*
* @param JSON <#JSON description#>
*/
- (void)populateObjectFromJSON:(id _Nullable)JSON;
/**
* <#Description#>
*
* @param JSON <#JSON description#>
* @param fromLocal <#fromLocal description#>
*/
- (void) populateObjectFromJSON:(id _Nullable)JSON fromLocal:(BOOL) fromLocal;
/**
* <#Description#>
*
* @param obj <#obj description#>
*
* @return <#return value description#>
*/
- (BOOL)isObjNull:(id _Nullable)obj;
/**
* <#Description#>
*
* @return <#return value description#>
*/
+ (NSArray * _Nonnull) protectedProperties;
/**
* <#Description#>
*
* @param PNObjClass <#PNObjClass description#>
*
* @return <#return value description#>
*/
+ (NSDictionary * _Nullable)propertiesForClass:(Class _Nonnull)PNObjClass;
/**
* <#Description#>
*
* @param mappingSelector <#mappingSelector description#>
*
* @return <#return value description#>
*/
- (NSDictionary* _Nonnull) getFormObject:(SEL _Nonnull) dictionaryMappingSelector;
- (void)resetObject;
///--------------------------------------
#pragma mark - PNObject (Protected) Properties
///--------------------------------------
/**
* <#Description#>
*/
@property (nonatomic, strong, nonnull) PNObjectModel * objectModel;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSMutableDictionary * JSON;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable) NSString * endPoint;
/**
* <#Description#>
*/
@property (nonatomic) BOOL singleInstance;
@end
+499
View File
@@ -0,0 +1,499 @@
//
// PNObject+Protected.m
// Pods
//
// Created by Giuseppe Nucifora on 25/01/16.
//
//
#import "PNObject+Protected.h"
#import "PNObjectConstants.h"
#import <NSDate_Utils/NSDate+NSDate_Util.h>
#import "objc/runtime.h"
@implementation PNObject (Protected)
@dynamic endPoint;
@dynamic objectModel;
@dynamic JSON;
@dynamic singleInstance;
+ (NSArray * _Nonnull) protectedProperties {
return @[@"JSON",@"objectModel",@"objectMapping",@"singleInstance"];
}
- (void) populateObjectFromJSON:(id)JSON {
return [self populateObjectFromJSON:JSON fromLocal:NO];
}
- (void) populateObjectFromJSON:(id _Nullable)JSON fromLocal:(BOOL) fromLocal {
NSDictionary *properties = [PNObject propertiesForClass:self.class];
for(NSString *propertyName in properties) {
if([propertyName isEqualToString:@"mappingError"])
continue;
NSString *mappedJSONKey;
NSString *mappedJSONType;
NSString *propertyType = [properties valueForKey:propertyName];
id mappingValue = [self.JSONObjectMap valueForKey:propertyName];
if([mappingValue isKindOfClass:NSDictionary.class]) {
mappedJSONKey = [mappingValue valueForKey:PNObjectMappingKey];
mappedJSONType = [mappingValue valueForKey:PNObjectMappingType];
} else {
mappedJSONKey = mappingValue;
}
/*if (fromLocal) {
propertyName = mappedJSONKey;
}*/
if ([[PNObject protectedProperties] containsObject:propertyName] || [self isObjNull:mappedJSONKey]) {
continue;
}
// Get JSON value for the mapped key
id value;
if (fromLocal) {
value = [JSON valueForKeyPath:propertyName];
}
else {
value = [JSON valueForKeyPath:mappedJSONKey];
}
if([self isObjNull:value]) {
continue;
}
((void (^)())@{
@"c" : ^{
char val = [value charValue];
[self setValue:@(val) forKey:propertyName];
},
@"d" : ^{
double val = [value doubleValue];
[self setValue:@(val) forKey:propertyName];
},
@"f" : ^{
float val = [value floatValue];
[self setValue:@(val) forKey:propertyName];
},
@"i" : ^{
int val = [value intValue];
[self setValue:@(val) forKey:propertyName];
},
@"l" : ^{
long val = [value longValue];
[self setValue:@(val) forKey:propertyName];
},
@"s" : ^{
short val = [value shortValue];
[self setValue:@(val) forKey:propertyName];
},
@"B" : ^{
BOOL val = [value boolValue];
[self setValue:@(val) forKey:propertyName];
},
@"q" : ^{
NSInteger val = [value integerValue];
[self setValue:@(val) forKey:propertyName];
},
@"NSString" : ^{
if (![self isObjNull:value]) {
[self setValue:value forKey:propertyName];
}
},
@"NSNumber" : ^{
NSNumber *val = [NSNumber numberWithDouble:[value doubleValue]];
[self setValue:val forKey:propertyName];
},
@"NSDate" : ^{
NSString *str = [NSString stringWithFormat:@"%@", value];
NSDate *val = [[NSDate dateFromString:str withFormat:kNSDateHelperFormatSQLDateWithTime] toLocalTime];
if (![self isObjNull:val]) {
[self setValue:val forKey:propertyName];
}
},
@"NSURL" : ^{
NSString *str = [NSString stringWithFormat:@"%@", value];
NSURL *val = [NSURL URLWithString:str];
[self setValue:val forKey:propertyName];
},
@"NSArray" : ^{
NSMutableArray *arr = [NSMutableArray array];
for(id JSONObject in value) {
if(fromLocal || [[JSONObject class] isSubclassOfClass:[PNObject class]] || [NSClassFromString(mappedJSONType) isSubclassOfClass:[PNObject class]]) {
PNObject *val = [[NSClassFromString(mappedJSONType) alloc] initWithJSON:JSONObject fromLocal:fromLocal];
[arr addObject:val];
}
else {
[arr addObject:JSONObject];
}
}
[self setValue:arr forKey:propertyName];
},
@"NSMutableArray" : ^{
NSMutableArray *arr = [NSMutableArray array];
for(id JSONObject in value) {
if(fromLocal || [[JSONObject class] isSubclassOfClass:[PNObject class]] || [NSClassFromString(mappedJSONType) isSubclassOfClass:[PNObject class]]) {
PNObject *val = [[NSClassFromString(mappedJSONType) alloc] initWithJSON:JSONObject fromLocal:fromLocal];
[arr addObject:val];
}
else {
[arr addObject:JSONObject];
}
}
[self setValue:arr forKey:propertyName];
}
}[propertyType] ?: ^{
BOOL isPNObjectSubclass = [NSClassFromString(propertyType) isSubclassOfClass:[PNObject class]];
if(isPNObjectSubclass) {
PNObject *val = [[NSClassFromString(propertyType) alloc] initWithJSON:value fromLocal:fromLocal];
[self setValue:val forKey:propertyName];
}
else {
NSString *errorStr = [NSString stringWithFormat:@"Property '%@' could not be assigned any value.", propertyName];
NSLogDebug(@"%@",errorStr);
}
})();
}
}
- (void)resetObject
{
NSDictionary *properties = [PNObject propertiesForClass:self.class];
for(NSString *propertyName in properties) {
if([propertyName isEqualToString:@"mappingError"])
continue;
NSString *mappedJSONKey;
NSString *mappedJSONType;
NSString *propertyType = [properties valueForKey:propertyName];
id mappingValue = [self.JSONObjectMap valueForKey:propertyName];
if([mappingValue isKindOfClass:NSDictionary.class]) {
mappedJSONKey = [mappingValue valueForKey:PNObjectMappingKey];
mappedJSONType = [mappingValue valueForKey:PNObjectMappingType];
} else {
mappedJSONKey = mappingValue;
}
if ([[PNObject protectedProperties] containsObject:propertyName]
|| [propertyName isEqualToString:@"description"]
|| [propertyName isEqualToString:@"debugDescription"]) {
continue;
}
// Get JSON value for the mapped key
((void (^)())@{
@"c" : ^{
char val = '\0';
[self setValue:@(val) forKey:propertyName];
},
@"d" : ^{
double val = 0.0;
[self setValue:@(val) forKey:propertyName];
},
@"f" : ^{
float val = 0.0;
[self setValue:@(val) forKey:propertyName];
},
@"i" : ^{
int val = 0;
[self setValue:@(val) forKey:propertyName];
},
@"l" : ^{
long val = 0;
[self setValue:@(val) forKey:propertyName];
},
@"s" : ^{
short val = 0;
[self setValue:@(val) forKey:propertyName];
},
@"q" : ^{
NSInteger val = 0;
[self setValue:@(val) forKey:propertyName];
},
@"B" : ^{
[self setValue:@(NO) forKey:propertyName];
},
@"NSString" : ^{
[self setValue:[NSString string] forKey:propertyName];
},
@"NSNumber" : ^{
[self setValue:[[NSNumber alloc] init] forKey:propertyName];
},
@"NSDate" : ^{
[self setValue:[[NSDate alloc] init] forKey:propertyName];
},
@"NSArray" : ^{
[self setValue:[NSArray array] forKey:propertyName];
},
@"NSMutableArray" : ^{
[self setValue:[NSMutableArray array] forKey:propertyName];
}
}[propertyType] ?: ^{
BOOL isPNObjectSubclass = [NSClassFromString(propertyType) isSubclassOfClass:[PNObject class]];
if(isPNObjectSubclass) {
[self setValue:@"" forKey:propertyName];
}
else {
NSString *errorStr = [NSString stringWithFormat:@"Property '%@' could not be assigned any value.", propertyName];
NSLogDebug(@"%@",errorStr);
}
})();
}
}
- (NSDictionary* _Nonnull) getFormObject:(SEL _Nonnull) dictionaryMappingSelector
{
NSMutableDictionary *JSON = [NSMutableDictionary dictionary];
if ([[self class] respondsToSelector:dictionaryMappingSelector]) {
NSDictionary *properties = [PNObject propertiesForClass:self.class];
//NSDictionary *formMapping = [[self class] performSelector:dictionaryMappingSelector];
NSDictionary *formMapping;
NSMethodSignature *methodSig = [[self class] instanceMethodSignatureForSelector:dictionaryMappingSelector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
[invocation setSelector:dictionaryMappingSelector];
[invocation setTarget:formMapping];
[invocation invoke];
for (NSString *formMappingKey in formMapping) {
if ([[properties allKeys] containsObject:formMappingKey] && [properties objectForKey:formMappingKey]) {
id property = [self valueForKey:formMappingKey];
id formMappingValue = [formMapping objectForKey:formMappingKey];
NSString *mappedKey;
NSString *mappedType;
NSDictionary *mappedValues;
if ([formMappingValue isKindOfClass:[NSDictionary class]]) {
mappedKey = [formMappingValue valueForKey:@"key"];
mappedType = [formMappingValue valueForKey:@"type"];
mappedValues = [formMappingValue valueForKey:@"values"];
}
else {
mappedKey = formMappingKey;
}
((void (^)())@{
@"c" : ^{
char val = [property charValue];
[JSON setValue:@(val) forKey:mappedKey];
},
@"d" : ^{
double val = [property doubleValue];
[JSON setValue:@(val) forKey:mappedKey];
},
@"f" : ^{
float val = [property floatValue];
[JSON setValue:@(val) forKey:mappedKey];
},
@"i" : ^{
int val = [property intValue];
[JSON setValue:@(val) forKey:mappedKey];
},
@"l" : ^{
long val = [property longValue];
[JSON setValue:@(val) forKey:mappedKey];
},
@"s" : ^{
short val = [property shortValue];
[JSON setValue:@(val) forKey:mappedKey];
},
@"B" : ^{
BOOL val = [property boolValue];
[JSON setValue:@(val) forKey:mappedKey];
},
@"q" : ^{
NSInteger val = [property integerValue];
[JSON setValue:@(val) forKey:mappedKey];
},
@"UIImage" : ^{
UIImage *image = [UIImage imageWithData:property];
[JSON setValue:image forKey:mappedKey];
},
@"NSURL" : ^{
NSURL *url = property;
if (![self isObjNull:url]) {
[JSON setValue:[url absoluteString] forKey:mappedKey];
}
},
@"NSString" : ^{
NSString *val = [NSString stringWithFormat:@"%@", property];
if (![self isObjNull:val]) {
[JSON setValue:val forKey:mappedKey];
}
},
@"NSNumber" : ^{
NSNumber *val = [NSNumber numberWithDouble:[property doubleValue]];
[JSON setValue:val forKey:mappedKey];
},
@"NSDate" : ^{
NSDate *val = [property toLocalTime];
if (![self isObjNull:val]) {
[JSON setValue:val forKey:mappedKey];
}
},
@"NSArray" : ^{
NSMutableArray *arr = [NSMutableArray array];
for(id object in property) {
BOOL isPNObjectSubclass = [[object class] isSubclassOfClass:[PNObject class]];
if(isPNObjectSubclass) {
NSDictionary *objectDict = [(PNObject*) object getFormObject:dictionaryMappingSelector];
[arr addObject:objectDict];
}
else {
[arr addObject:object];
}
}
[JSON setValue:arr forKey:mappedKey];
},
@"NSMutableArray" : ^{
NSMutableArray *arr = [NSMutableArray array];
for(id object in property) {
BOOL isPNObjectSubclass = [[object class] isSubclassOfClass:[PNObject class]];
if(isPNObjectSubclass) {
NSDictionary *objectDict = [(PNObject*) object getFormObject:dictionaryMappingSelector];
[arr addObject:objectDict];
}
else {
[arr addObject:object];
}
}
[JSON setValue:arr forKey:mappedKey];
}
}[[property class]] ?: ^{
BOOL isPNObjectSubclass = [[property class] isSubclassOfClass:[PNObject class]];
if(isPNObjectSubclass) {
NSDictionary *objectDict = [(PNObject*)property getFormObject:dictionaryMappingSelector];
[JSON setValue:objectDict forKey:mappedKey];
}
else {
NSString *errorStr = [NSString stringWithFormat:@"Property '%@' could not be assigned any value.", property];
NSLogDebug(@"%@",errorStr);
}
})();
}
}
}
return JSON;
}
- (BOOL)isObjNull:(id _Nullable)obj
{
if(!obj || nil == obj || NSNull.null == obj || ([obj isKindOfClass:[NSString class]] && [obj isEqualToString:@"(null)"]) || [obj isEqual:[NSNull null]])
return YES;
else
return NO;
}
static BOOL property_getTypeString( objc_property_t property, char *buffer )
{
const char * attrs = property_getAttributes( property );
if ( attrs == NULL )
return NO;
const char * e = strchr( attrs, ',' );
if ( e == NULL )
return NO;
int len = (int)(e - attrs);
memcpy( buffer, attrs, len );
buffer[len] = '\0';
return YES;
}
+ (NSDictionary *)propertiesForClass:(Class)PNObjClass
{
if (PNObjClass == NULL) {
return nil;
}
NSMutableDictionary *results = [NSMutableDictionary dictionary];
if ([PNObjClass isSubclassOfClass:[PNObject class]] && PNObjClass != [PNObject class]) {
[results addEntriesFromDictionary:[self propertiesForClass:class_getSuperclass(PNObjClass)]];
}
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList(PNObjClass, &outCount);
for (i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
const char *propName = property_getName(property);
if(propName) {
//const char *propType = getPropertyType(property);
char propType[256];
if (!property_getTypeString(property, propType)) {
continue;
}
NSString *propertyName = [NSString stringWithUTF8String:propName];
NSString *propertyType = [NSString stringWithUTF8String:propType];
NSRange range = [propertyType rangeOfString:@"T@\""];
NSRange range2 = [propertyType rangeOfString:@"T"];
if (range.location != NSNotFound) {
NSRange subStrRange = NSMakeRange(range.length, propertyType.length - (range.length + 1));
propertyType = [propertyType substringWithRange:subStrRange];
}
else if (range2.location != NSNotFound) {
NSRange subStrRange = NSMakeRange(range2.length, propertyType.length - (range2.length));
propertyType = [propertyType substringWithRange:subStrRange];
}
//NSLogDebug(@"Prop type & name: %@ -- %@", propertyType, propertyName);
if (![[PNObject protectedProperties] containsObject:propertyName]) {
[results setObject:propertyType forKey:propertyName];
}
}
}
free(properties);
// returning a copy here to make sure the dictionary is immutable
return [NSDictionary dictionaryWithDictionary:results];
}
@end
+80
View File
@@ -0,0 +1,80 @@
//
// PNObject.h
// Pods
//
// Created by Giuseppe Nucifora on 28/12/15.
//
//
#import <Foundation/Foundation.h>
#import "PNObjectConfig.h"
#import "PNObjectModel.h"
#import "PNObjectUtilities.h"
#import "PNObjectConstants.h"
#pragma mark MappingSelector Keys
extern NSString* _Nonnull const PNObjectMappingKey;
extern NSString* _Nonnull const PNObjectMappingType;
extern NSString* _Nonnull const PNObjectMappingSelector;
#pragma mark -
@protocol PNObjectSubclassing <NSObject>
@required
+ (NSDictionary * _Nonnull) objcetMapping;
+ (BOOL) singleInstance;
+ (NSString * _Nonnull) objectEndPoint;
@optional
+ (NSString * _Nonnull ) objectClassName;
@end
@interface PNObject : NSObject
+ (NSString * _Nonnull) PNObjClassName;
+ (NSString * _Nonnull) PNObjEndPoint;
+ (NSArray * _Nonnull) batch:(id _Nonnull)JSON fromLocal:(BOOL) fromLocal;
- (_Nullable instancetype) initWithLocalJSON:( NSDictionary * _Nonnull) JSON;
- (_Nullable instancetype) initWithRemoteJSON:( NSDictionary * _Nonnull) JSON;
- (_Nullable instancetype) initWithJSON:( NSDictionary * _Nonnull) JSON fromLocal:(BOOL) fromLocal;
- (id _Nonnull) saveLocally;
- (BOOL) autoRemoveLocally;
- (NSDictionary * _Nonnull) JSONFormObject;
- (NSDictionary * _Nonnull) reverseMapping;
///--------------------------------------
#pragma mark - PNObject Properties
///--------------------------------------
@property (nonatomic, strong, nonnull) NSString *objID;
/**
* <#Description#>
*/
@property (nonatomic, strong, nonnull) NSString * localObjID;
/**
* <#Description#>
*/
@property (nonatomic, strong, nonnull) NSDate * createdAt;
/**
* <#Description#>
*/
@property (nonatomic, strong, nonnull) NSDictionary * JSONObjectMap;
@end
+598
View File
@@ -0,0 +1,598 @@
//
// PNObject.m
// Pods
//
// Created by Giuseppe Nucifora on 28/12/15.
//
//
#import "PNObject.h"
#import <NSDate_Utils/NSDate+NSDate_Util.h>
#import <AFNetworking/AFNetworking.h>
#import "PNObject/PNUser.h"
#import "PNObjectConstants.h"
#import "PNObject+Protected.h"
#import "objc/runtime.h"
#import "PNObject+PNObjectConnection.m"
#import <RZDataBinding/RZDataBinding.h>
#import "HTTPStatusCodes.h"
#define PNOBJECT_DIR @"PNObjects"
NSString * const PNObjectMappingKey = @"key";
NSString * const PNObjectMappingType = @"type";
NSString * const PNObjectMappingSelector = @"selector";
@interface PNObject() <PNObjectPersistency,PNObjectSubclassing>
@property (nonatomic, strong) PNObjectModel * _Nonnull objectModel;
@property (nonatomic, strong) NSMutableDictionary * _Nonnull JSON;
@property (nonatomic, strong) NSString * _Nonnull endPoint;
@property (nonatomic) BOOL singleInstance;
@end
@implementation PNObject
#pragma mark PNObjectSubclassing
+ (NSDictionary *) objcetMapping {
NSDictionary *mapping = @{@"objID":@"uuid",
@"localObjID":@"localObjID",
@"createdAt":@"created_at",
};
return mapping;
}
+ (NSString *)objectEndPoint {
return NSStringFromClass([self class]);
}
+ (BOOL) singleInstance {
return NO;
}
+ (NSString*) objectClassName {
return NSStringFromClass([self class]);
}
#pragma mark -
+ (NSString * _Nonnull) PNObjClassName {
if ([[self class] resolveClassMethod:@selector(objectClassName)]) {
return [[self class] objectClassName];
}
else {
return [[super class] objectClassName];
}
}
+ (NSString * _Nonnull) PNObjEndPoint {
if ([[self class] resolveClassMethod:@selector(objectEndPoint)]) {
return [[self class] objectEndPoint];
}
else {
return [[super class] objectEndPoint];
}
}
- (_Nullable instancetype) init {
self = [super init];
if (self) {
if ([[self class] isSubclassOfClass:[PNObject class]]) {
NSAssert([[self class] conformsToProtocol:@protocol(PNObjectSubclassing)], @"Subclass object must conform to PNObjectSubclassing");
_localObjID = [[NSProcessInfo processInfo] globallyUniqueString];
self.objectModel = [PNObjectModel sharedInstance];
[self.objectModel setPersistencyDelegate:self];
NSMutableDictionary * objectDict = [[NSMutableDictionary alloc] initWithDictionary:[[self class] objcetMapping]];
[objectDict addEntriesFromDictionary:[PNObject objcetMapping]];
self.JSONObjectMap = objectDict;
NSAssert(self.JSONObjectMap, @"You must create objectMapping");
self.singleInstance = [[self class] singleInstance];
self.createdAt = [[NSDate date] toLocalTime];
}
self.JSON = [[NSMutableDictionary alloc] init];
NSDictionary *properties = [PNObject propertiesForClass:self.class];
for (NSString *propertyName in properties) {
if ([propertyName isEqualToString:@"description"] || [propertyName isEqualToString:@"debugDescription"]) {
continue;
}
//[self addObserver:self forKeyPath:propertyName options:NSKeyValueObservingOptionNew context:nil];
[self rz_addTarget:self action:@selector(valueChanged:) forKeyPathChange:propertyName];
NSString *propertyType = [properties valueForKey:propertyName];
((void (^)())@{
@"NSMutableArray" : ^{
NSMutableArray *arr = [[NSMutableArray alloc] init];
[self setValue:arr forKey:propertyName];
}
}[propertyType] ?: ^{
})();
}
}
return self;
}
- (_Nullable instancetype) initWithRemoteJSON:( NSDictionary * _Nonnull) JSON {
return [self initWithJSON:JSON fromLocal:NO];
}
- (_Nullable instancetype) initWithLocalJSON:( NSDictionary * _Nonnull) JSON {
return [self initWithJSON:JSON fromLocal:YES];
}
- (_Nullable instancetype) initWithJSON:( NSDictionary * _Nonnull) JSON fromLocal:(BOOL) fromLocal {
self = [super init];
if (self) {
if ([[self class] isSubclassOfClass:[PNObject class]]) {
NSAssert([[self class] conformsToProtocol:@protocol(PNObjectSubclassing)], @"Subclass object must conform to PNObjectSubclassing Protocol");
_localObjID = [[NSProcessInfo processInfo] globallyUniqueString];
self.objectModel = [PNObjectModel sharedInstance];
[self.objectModel setPersistencyDelegate:self];
NSMutableDictionary * objectDict = [[NSMutableDictionary alloc] initWithDictionary:[[self class] objcetMapping]];
[objectDict addEntriesFromDictionary:[PNObject objcetMapping]];
self.JSONObjectMap = objectDict;
NSAssert(self.JSONObjectMap, @"You must create objectMapping");
self.singleInstance = [[self class] singleInstance];
_createdAt = [[NSDate date] toLocalTime];
}
NSDictionary *properties = [PNObject propertiesForClass:self.class];
for (NSString *propertyName in properties) {
if ([propertyName isEqualToString:@"description"] || [propertyName isEqualToString:@"debugDescription"]) {
continue;
}
//[self addObserver:self forKeyPath:propertyName options:NSKeyValueObservingOptionNew context:nil];
[self rz_addTarget:self action:@selector(valueChanged:) forKeyPathChange:propertyName];
NSString *propertyType = [properties valueForKey:propertyName];
((void (^)())@{
@"NSMutableArray" : ^{
NSMutableArray *arr = [[NSMutableArray alloc] init];
[self setValue:arr forKey:propertyName];
}
}[propertyType] ?: ^{
})();
}
NSAssert(self.JSONObjectMap, @"You must create objectMapping");
self.JSON = [[NSMutableDictionary alloc] initWithDictionary:JSON];
[self populateObjectFromJSON:self.JSON fromLocal:fromLocal];
}
return self;
}
- (NSDictionary * _Nonnull) reverseMapping
{
NSMutableDictionary *JSON = [[NSMutableDictionary alloc] init];
NSString *mappedJSONKey;
NSString *mappedJSONType;
NSString *type;
NSDictionary *properties = [PNObject propertiesForClass:self.class];
for (NSString* propertyName in self.JSONObjectMap) {
id mappingValue = [self.JSONObjectMap objectForKey:propertyName];
if([mappingValue isKindOfClass:NSDictionary.class]) {
mappedJSONKey = [mappingValue valueForKey:PNObjectMappingKey];
mappedJSONType = [mappingValue valueForKey:PNObjectMappingType];
} else {
mappedJSONKey = mappingValue;
mappedJSONType = [properties valueForKey:propertyName];
}
type = [properties valueForKey:propertyName];
NSLog(@"PropertyName MappedJsonType PropertyType: %@ - %@ - %@",propertyName,mappedJSONType,type);
id value;
@try {
value = [self valueForKey:propertyName];
((void (^)())@{
@"c" : ^{
char val = [value charValue];
[JSON setValue:@(val) forKey:propertyName];
},
@"d" : ^{
double val = [value doubleValue];
[JSON setValue:@(val) forKey:propertyName];
},
@"f" : ^{
float val = [value floatValue];
[JSON setValue:@(val) forKey:propertyName];
},
@"i" : ^{
int val = [value intValue];
[JSON setValue:@(val) forKey:propertyName];
},
@"l" : ^{
long val = [value longValue];
[JSON setValue:@(val) forKey:propertyName];
},
@"s" : ^{
short val = [value shortValue];
[JSON setValue:@(val) forKey:propertyName];
},
@"B" : ^{
BOOL val = [value boolValue];
[JSON setValue:@(val) forKey:propertyName];
},
@"q" : ^{
NSInteger val = [value integerValue];
[JSON setValue:@(val) forKey:propertyName];
},
@"NSURL" : ^{
NSURL *url = value;
if (![self isObjNull:url]) {
[JSON setValue:[url absoluteString] forKey:propertyName];
}
},
@"NSString" : ^{
NSString *val = [NSString stringWithFormat:@"%@", value];
if (![self isObjNull:val]) {
[JSON setValue:val forKey:propertyName];
}
},
@"NSNumber" : ^{
NSInteger val = [value integerValue];
[JSON setValue:@(val) forKey:propertyName];
},
@"NSDate" : ^{
NSDate *val = [value toLocalTime];
if (![self isObjNull:val]) {
[JSON setValue:val forKey:propertyName];
}
},
@"NSArray" : ^{
NSMutableArray *arr = [NSMutableArray array];
for(id object in value) {
BOOL isPNObjectSubclass = [[object class] isSubclassOfClass:[PNObject class]];
if(isPNObjectSubclass) {
NSDictionary *objectDict = [(PNObject*) object reverseMapping];
[arr addObject:objectDict];
}
else {
[arr addObject:object];
}
}
[JSON setValue:arr forKey:propertyName];
},
@"NSMutableArray" : ^{
NSMutableArray *arr = [NSMutableArray array];
for(id object in value) {
BOOL isPNObjectSubclass = [[object class] isSubclassOfClass:[PNObject class]];
if(isPNObjectSubclass) {
NSDictionary *objectDict = [(PNObject*) object reverseMapping];
[arr addObject:objectDict];
}
else {
[arr addObject:object];
}
}
[JSON setValue:arr forKey:propertyName];
}
}[type] ?: ^{
BOOL isPNObjectSubclass = [NSClassFromString(mappedJSONType) isSubclassOfClass:[PNObject class]];
if(isPNObjectSubclass) {
NSDictionary *objectDict = [(PNObject*)value reverseMapping];
[JSON setValue:objectDict forKey:propertyName];
}
else {
// do nothing
[JSON setValue:value forKey:propertyName];
}
})();
}
@catch (NSException *exception) {
continue;
}
@finally {
//NSLog(@"PropertyName PropertyType Value: %@ - %@ - %@",propertyName,propertyType,value);
}
}
if (self.JSON && [[self.JSON allKeys] count] == 0) {
self.JSON = JSON;
}
return JSON;
}
- (NSDictionary * _Nonnull) JSONFormObject {
NSMutableDictionary *JSONFormObject = [[NSMutableDictionary alloc] init];
NSString *mappedJSONKey;
NSString *mappedJSONType;
NSDictionary *properties = [PNObject propertiesForClass:self.class];
for (NSString* propertyName in self.JSONObjectMap) {
id mappingValue = [self.JSONObjectMap objectForKey:propertyName];
if([mappingValue isKindOfClass:NSDictionary.class]) {
mappedJSONKey = [mappingValue valueForKey:@"key"];
mappedJSONType = [mappingValue valueForKey:@"type"];
} else {
mappedJSONKey = mappingValue;
mappedJSONType = [properties valueForKey:propertyName];
}
NSLog(@"PropertyName PropertyType: %@ - %@",propertyName,mappedJSONType);
id value;
@try {
value = [self valueForKey:propertyName];
((void (^)())@{
@"c" : ^{
char val = [value charValue];
[JSONFormObject setValue:@(val) forKey:propertyName];
},
@"d" : ^{
double val = [value doubleValue];
[JSONFormObject setValue:@(val) forKey:propertyName];
},
@"f" : ^{
float val = [value floatValue];
[JSONFormObject setValue:@(val) forKey:propertyName];
},
@"i" : ^{
int val = [value intValue];
[JSONFormObject setValue:@(val) forKey:propertyName];
},
@"l" : ^{
long val = [value longValue];
[JSONFormObject setValue:@(val) forKey:propertyName];
},
@"s" : ^{
short val = [value shortValue];
[JSONFormObject setValue:@(val) forKey:propertyName];
},
@"B" : ^{
BOOL val = [value boolValue];
[JSONFormObject setValue:@(val) forKey:propertyName];
},
@"q" : ^{
NSInteger val = [value integerValue];
[JSONFormObject setValue:@(val) forKey:propertyName];
},
@"NSURL" : ^{
NSURL *url = value;
if (![self isObjNull:url]) {
[JSONFormObject setValue:[url absoluteString] forKey:propertyName];
}
},
@"NSString" : ^{
NSString *val = [NSString stringWithFormat:@"%@", value];
if (![self isObjNull:val]) {
[JSONFormObject setValue:val forKey:propertyName];
}
},
@"NSNumber" : ^{
NSInteger val = [value integerValue];
[JSONFormObject setValue:@(val) forKey:propertyName];
},
@"NSDate" : ^{
NSString *val = [[value toLocalTime] stringWithFormat:kNSDateHelperFormatSQLDateWithTime];
if (![self isObjNull:val]) {
[JSONFormObject setValue:val forKey:propertyName];
}
},
@"NSArray" : ^{
NSMutableArray *arr = [NSMutableArray array];
for(id object in value) {
BOOL isPNObjectSubclass = [[object class] isSubclassOfClass:[PNObject class]];
if(isPNObjectSubclass) {
NSDictionary *objectDict = [(PNObject*) object JSONFormObject];
[arr addObject:objectDict];
}
else {
[arr addObject:object];
}
}
[JSONFormObject setValue:arr forKey:mappedJSONKey];
},
@"NSMutableArray" : ^{
NSMutableArray *arr = [NSMutableArray array];
for(id object in value) {
BOOL isPNObjectSubclass = [[object class] isSubclassOfClass:[PNObject class]];
if(isPNObjectSubclass) {
NSDictionary *objectDict = [(PNObject*) object JSONFormObject];
[arr addObject:objectDict];
}
else {
[arr addObject:object];
}
}
[JSONFormObject setValue:arr forKey:mappedJSONKey];
}
}[mappedJSONType] ?: ^{
BOOL isPNObjectSubclass = [NSClassFromString(mappedJSONType) isSubclassOfClass:[PNObject class]];
if(isPNObjectSubclass) {
NSDictionary *objectDict = [(PNObject*)value JSONFormObject];
[JSONFormObject setValue:objectDict forKey:mappedJSONKey];
}
else {
// do nothing
[JSONFormObject setValue:value forKey:propertyName];
}
})();
}
@catch (NSException *exception) {
continue;
}
@finally {
//NSLog(@"PropertyName PropertyType Value: %@ - %@ - %@",propertyName,propertyType,value);
}
}
return JSONFormObject;
}
- (NSString* _Nonnull) description {
return [[self reverseMapping] description];
}
- (void) setSingleInstance:(BOOL)singleInstance {
_singleInstance = singleInstance;
}
#pragma mark PNObjectPersistency protocol
- (BOOL) initObjectPersistency {
BOOL isDir=YES;
NSError *error;
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSFileManager *fileManager= [NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:[docDir stringByAppendingFormat:@"/%@",PNOBJECT_DIR] isDirectory:&isDir]) {
if (![[NSFileManager defaultManager] createDirectoryAtPath:[docDir stringByAppendingFormat:@"/%@",PNOBJECT_DIR] withIntermediateDirectories:NO attributes:nil error:&error]) {
#ifdef DEBUG
NSLogDebug(@"Create directory error: %@", error);
#endif
return NO;
}
}
#ifdef DEBUG
NSLogDebug(@"%@",[docDir stringByAppendingFormat:@"/%@",PNOBJECT_DIR]);
#endif
return YES;
}
- (id _Nonnull) saveLocally {
__weak id weakSelf = self;
return [self.objectModel saveLocally:weakSelf];
}
- (BOOL) autoRemoveLocally {
return [self.objectModel removeObjectLocally:self];
}
+ (NSArray *)batch:(id)JSON fromLocal:(BOOL) fromLocal
{
NSString *className = NSStringFromClass([self class]);
NSMutableArray *batch = [NSMutableArray array];
for(id objectJSON in JSON) {
PNObject *val = [[NSClassFromString(className) alloc] initWithJSON:objectJSON fromLocal:fromLocal];
[batch addObject:val];
}
return batch;
}
#pragma mark -
/*
NSString* const kRZDBChangeKeyObject = @"RZDBChangeObject";
NSString* const kRZDBChangeKeyOld = @"RZDBChangeOld";
NSString* const kRZDBChangeKeyNew = @"RZDBChangeNew";
NSString* const kRZDBChangeKeyKeyPath = @"RZDBChangeKeyPath";
*/
- (void) valueChanged:(NSDictionary *) value {
if ([value objectForKey:kRZDBChangeKeyNew]) {
if ([[[value objectForKey:kRZDBChangeKeyNew] class] isSubclassOfClass:[PNObject class]]) {
NSDictionary *objectDict = [(PNObject*)[value objectForKey:kRZDBChangeKeyNew] reverseMapping];
if ([[[[self class] objcetMapping] allKeys] containsObject:[value objectForKey:kRZDBChangeKeyKeyPath]]) {
[self.JSON setValue:objectDict forKey:[[[self class] objcetMapping] objectForKey:[value objectForKey:kRZDBChangeKeyKeyPath]]];
}
}
else {
if ([[[[self class] objcetMapping] allKeys] containsObject:[value objectForKey:kRZDBChangeKeyKeyPath]]) {
[self.JSON setValue:[value objectForKey:kRZDBChangeKeyNew] forKey:[[[self class] objcetMapping] objectForKey:[value objectForKey:kRZDBChangeKeyKeyPath]]];
}
}
}
}
- (void)dealloc
{
_JSON = nil;
_JSONObjectMap = nil;
_objID = nil;
_localObjID = nil;
_createdAt = nil;
}
@end
+249
View File
@@ -0,0 +1,249 @@
//
// PNObjectConfig.h
// Pods
//
// Created by Giuseppe Nucifora on 08/01/16.
//
//
#import <Foundation/Foundation.h>
#import <AFNetworking/AFNetworking.h>
//#import "HTTPStatusCodes"
#import "AFOAuth2Manager.h"
#import "AFHTTPRequestSerializer+OAuth2.h"
#import "AFOAuthCredential.h"
extern NSString* _Nonnull const PNObjectEncryptionKey;
extern NSString* _Nonnull const PNObjectEncryptionNonce;
#pragma mark LocalNotification Keys
extern NSString* _Nonnull const PNObjectLocalNotificationRefreshTokenClientCredentialSuccess;
extern NSString* _Nonnull const PNObjectLocalNotificationRefreshTokenClientCredentialFail;
extern NSString* _Nonnull const PNObjectLocalNotificationRefreshTokenUserSuccess;
extern NSString* _Nonnull const PNObjectLocalNotificationRefreshTokenUserFail;
extern NSString* _Nonnull const PNObjectLocalNotificationUserReloadFromServerSuccess;
extern NSString* _Nonnull const PNObjectLocalNotificationUserReloadFromServerFailure;
extern NSString* _Nonnull const PNObjectLocalNotificationUserWillLogout;
extern NSString* _Nonnull const PNObjectLocalNotificationUserEndLogout;
extern NSString* _Nonnull const PNObjectLocalNotificationPNInstallationUserNew;
extern NSString* _Nonnull const PNObjectLocalNotificationPNInstallationUserChange;
extern NSString* _Nonnull const PNObjectLocalNotificationPNInstallationUserDelete;
#pragma mark -
extern NSString* _Nonnull const EnvironmentProduction;
extern NSString* _Nonnull const EnvironmentStage;
extern NSString* _Nonnull const EnvironmentDevelopment;
extern NSString* _Nonnull const Client_ID;
extern NSString* _Nonnull const Client_Secret;
@interface PNObjectConfig : NSObject
/**
* gets singleton object.
* @return singleton
*/
+ (instancetype _Nonnull) sharedInstance;
/**
* Oauth is NO by default
*
* @param endpointUrlsForEnvironments
* For example,
* @{ PNObjectConfigDevelopment : @"https://development.it/api/v1",
* PNObjectConfigEnvStage : @"ttps://stage.it/api/v1",
* PNObjectConfigEnvProduction : @"ttps://production.it/api/v1"
* }
*
* @return singleton
*/
+ (instancetype _Nonnull) initSharedInstanceForEnvironments:(NSDictionary * _Nonnull) endpointUrlsForEnvironments;
/**
* <#Description#>
*
* @param endpointUrlsForEnvironments
* For example,
* @{ PNObjectConfigDevelopment : @"https://development.it/api/v1",
* PNObjectConfigEnvStage : @"ttps://stage.it/api/v1",
* PNObjectConfigEnvProduction : @"ttps://production.it/api/v1"
* }
* @param userSubClass <#userSubClass description#>
*
* @return <#return value description#>
*/
+ (instancetype _Nonnull) initSharedInstanceForEnvironments:(NSDictionary * _Nonnull) endpointUrlsForEnvironments andUserSubclass:(Class _Nonnull) userSubClass;
/**
*
*
* @param endpointUrlsForEnvironments
* For example,
* @{ PNObjectConfigDevelopment : @"https://development.it/api/v1",
* PNObjectConfigEnvStage : @"ttps://stage.it/api/v1",
* PNObjectConfigEnvProduction : @"ttps://production.it/api/v1"
* }
* @param oauthEnabled <#oauthEnabled description#>
*
* @return singleton
*/
+ (instancetype _Nonnull) initSharedInstanceForEnvironments:(NSDictionary * _Nonnull) endpointUrlsForEnvironments withOauth:(BOOL) oauthEnabled;
/**
* <#Description#>
*
* @param endpointUrlsForEnvironments
* For example,
* @{ PNObjectConfigDevelopment : @"https://development.it/api/v1",
* PNObjectConfigEnvStage : @"ttps://stage.it/api/v1",
* PNObjectConfigEnvProduction : @"ttps://production.it/api/v1"
* }
* @param userSubClass <#userSubClass description#>
* @param oauthEnabled <#oauthEnabled description#>
*
* @return <#return value description#>
*/
+ (instancetype _Nonnull) initSharedInstanceForEnvironments:(NSDictionary * _Nonnull) endpointUrlsForEnvironments userSubclass:(Class _Nonnull) userSubClass withOauth:(BOOL) oauthEnabled;
/**
* <#Description#>
*
* @param env <#env description#>
*/
- (void) setEnvironment:(NSString * _Nonnull) environment;
/**
* <#Description#>
*
* @param value <#value description#>
* @param key <#key description#>
*/
- (void) setHTTPHeaderValue:(NSString * _Nonnull)value forKey:(NSString * _Nonnull) key;
/**
* <#Description#>
*
* @param value EnvironmentProduction, EnvironmentStage, EnvironmentDevelopment
* @param key <#key description#>
*/
- (void) removeHTTPHeaderValueForKey:(NSString * _Nonnull) key;
- (void) setClientID:(NSString * _Nonnull) clientID clientSecret:(NSString* _Nonnull) clientSecret forEnv:(NSString * _Nonnull) environment;
/**
* <#Description#>
*
* @return <#return value description#>
*/
- (NSString * _Nonnull) baseUrl;
/**
* <#Description#>
*
* @param passLenght <#passLenght description#>
*/
- (void) setAcceptablePasswordLenght:(NSUInteger) passLenght;
/**
* This method refresh current token and automanage if token type is client credential or user token
*/
- (void) refreshToken;
/**
* This method refresh current token and automanage if token type is client credential or user token and returns block success and failure
*
* @param success <#success description#>
* @param failure <#failure description#>
*/
- (void) refreshTokenWithBlockSuccess:(nullable void (^)(BOOL refreshSuccess))success
failure:(nullable void (^)(NSError * _Nonnull error))failure;
/**
* <#Description#>
*/
- (void) refreshTokenForClientCredential;
/**
* <#Description#>
*
* @param success <#success description#>
* @param failure <#failure description#>
*/
- (void) refreshTokenForClientCredentialWithBlockSuccess:(nullable void (^)(BOOL refreshSuccess))success
failure:(nullable void (^)(NSError * _Nonnull error))failure;
/**
* <#Description#>
*/
- (void) refreshTokenForUser;
/**
* <#Description#>
*
* @param success <#success description#>
* @param failure <#failure description#>
*/
- (void) refreshTokenForUserWithBlockSuccess:(nullable void (^)(BOOL refreshSuccess))success
failure:(nullable void (^)(NSError * _Nonnull error))failure;
/**
* <#Description#>
*
* @param email <#email description#>
* @param password <#password description#>
* @param success <#success description#>
* @param failure <#failure description#>
*/
- (void) refreshTokenForUserWithEmail:(NSString * _Nonnull) email
password:(NSString * _Nonnull) password
withBlockSuccess:(nullable void (^)(BOOL refreshSuccess))success
failure:(nullable void (^)(NSError * _Nonnull error))failure;
- (void) refreshTokenForUserWithFacebookID:(NSString * _Nonnull) facebookID
facebookToken:(NSString * _Nonnull) facebookToken
withBlockSuccess:(nullable void (^)(BOOL refreshSuccess))success
failure:(nullable void (^)(NSError * _Nonnull error))failure;
/**
* <#Description#>
*/
- (BOOL) resetToken;
///--------------------------------------
#pragma mark - PNObjectConfig Properties
///--------------------------------------
@property (nonatomic, readonly, nonnull) Class userSubClass;
/**
* <#Description#>
*/
@property (nonatomic, strong, readonly, nonnull) AFHTTPSessionManager *manager;
/**
* <#Description#>
*/
@property (nonatomic, strong, readonly, nonnull) AFJSONRequestSerializer *jsonSerializer;
/**
* <#Description#>
*/
@property (nonatomic, strong, readonly, nonnull) AFHTTPRequestSerializer *httpSerializer;
/**
* <#Description#>
*/
@property (nonatomic, strong, nullable, readonly) AFOAuthCredential *currentOauthCredential;
/**
* <#Description#>
*/
@property (nonatomic) NSInteger minPasswordLenght;
@end
+569
View File
@@ -0,0 +1,569 @@
//
// PNObjectConfig.m
// Pods
//
// Created by Giuseppe Nucifora on 08/01/16.
//
//
#import "PNObjectConfig.h"
#import "PNObjectConstants.h"
#import "PNUser.h"
#import "AFJSONResponseSerializerWithData.h"
#import "NSString+Helper.h"
#import "PNObject+Protected.h"
#import "NSUserDefaults+AESEncryptor.h"
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <NAChloride/NAChloride.h>
#import <DDDKeychainWrapper/DDDKeychainWrapper.h>
#import "HTTPStatusCodes.h"
NSString * const PNObjectLocalNotificationRefreshTokenClientCredentialSuccess = @"PNObjectLocalNotificationRefreshTokenClientCredentialSuccess";
NSString * const PNObjectLocalNotificationRefreshTokenClientCredentialFail = @"PNObjectLocalNotificationRefreshTokenClientCredentialFail";
NSString * const PNObjectLocalNotificationRefreshTokenUserSuccess = @"PNObjectLocalNotificationRefreshTokenUserSuccess";
NSString * const PNObjectLocalNotificationRefreshTokenUserFail = @"PNObjectLocalNotificationRefreshTokenUserFail";
NSString * const PNObjectLocalNotificationUserReloadFromServerSuccess = @"PNObjectLocalNotificationUserReloadFromServerSuccess";
NSString * const PNObjectLocalNotificationUserReloadFromServerFailure = @"PNObjectLocalNotificationUserReloadFromServerFailure";
NSString * const PNObjectLocalNotificationUserWillLogout = @"PNObjectLocalNotificationUserLogout";
NSString * const PNObjectLocalNotificationUserEndLogout = @"PNObjectLocalNotificationUserLogout";
NSString * const PNObjectLocalNotificationPNInstallationUserNew = @"PNObjectLocalNotificationPNInstallationUserNew";
NSString * const PNObjectLocalNotificationPNInstallationUserChange = @"PNObjectLocalNotificationPNInstallationUserChange";
NSString * const PNObjectLocalNotificationPNInstallationUserDelete = @"PNObjectLocalNotificationPNInstallationUserDelete";
NSInteger const minPassLenght = 4;
NSString * const PNObjectEncryptionKey = @"PNObjectConfigEncryptionKey";
NSString * const PNObjectEncryptionNonce = @"PNObjectConfigEncryptionNonce";
NSString * const PNObjectServiceClientCredentialIdentifier = @"PNObjectServiceClientCredentialIdentifier";
NSString * const PNObjectServiceUserCredentialIdentifier = @"PNObjectServiceUserCredentialIdentifier";
NSString* const EnvironmentProduction = @"PNObjectConfigEnvProduction";
NSString* const EnvironmentStage = @"PNObjectConfigEnvStage";
NSString* const EnvironmentDevelopment = @"PNObjectConfigDevelopment";
NSString* const BaseUrl = @"base_url";
NSString* const Client_ID = @"client_id";
NSString* const Client_Secret = @"client_secret";
@interface PNObjectConfig()
@property (nonatomic) BOOL oauthEnabled;
@property (nonatomic, strong) NSMutableDictionary *configuration;
@property (nonatomic, strong) NSMutableDictionary *headerFields;
@property (nonatomic, strong) NSString *currentEnv;
@property (nonatomic, strong) NSString *currentEndPointBaseUrl;
@property (nonatomic, strong) NSString *currentOAuthClientID;
@property (nonatomic, strong) NSString *currentOAuthClientSecret;
@property (nonatomic, strong) AFOAuth2Manager *authManager;
@end
@implementation PNObjectConfig
@synthesize manager = _manager;
static PNObjectConfig *SINGLETON_PNObjectConfig = nil;
static bool isFirstAccess = YES;
#pragma mark - Public Method
+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
isFirstAccess = NO;
SINGLETON_PNObjectConfig = [[super allocWithZone:NULL] initWithUserSubclass:[PNUser class] withOauth:NO];
});
return SINGLETON_PNObjectConfig;
}
#pragma mark - Life Cycle
+ (instancetype) initSharedInstanceForEnvironments:(NSDictionary *) endpointUrlsForEnvironments {
return [self initSharedInstanceForEnvironments:endpointUrlsForEnvironments userSubclass:[PNUser class] withOauth:NO];
}
+ (instancetype) initSharedInstanceForEnvironments:(NSDictionary *)endpointUrlsForEnvironments andUserSubclass:(Class)userSubClass {
return [self initSharedInstanceForEnvironments:endpointUrlsForEnvironments userSubclass:userSubClass withOauth:NO];
}
+ (instancetype) initSharedInstanceForEnvironments:(NSDictionary *) endpointUrlsForEnvironments withOauth:(BOOL) oauthEnabled {
return [self initSharedInstanceForEnvironments:endpointUrlsForEnvironments userSubclass:[PNUser class] withOauth:oauthEnabled];
}
+ (instancetype _Nonnull) initSharedInstanceForEnvironments:(NSDictionary * _Nonnull) endpointUrlsForEnvironments userSubclass:(Class _Nonnull) userSubClass withOauth:(BOOL) oauthEnabled {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
isFirstAccess = NO;
SINGLETON_PNObjectConfig = [[super allocWithZone:NULL] initWithUserSubclass:userSubClass withOauth:oauthEnabled];
if (SINGLETON_PNObjectConfig) {
for (NSString *key in [endpointUrlsForEnvironments allKeys]) {
NSURL * endpointUrl = [NSURL URLWithString:[endpointUrlsForEnvironments objectForKey:key]];
if (endpointUrl) {
[SINGLETON_PNObjectConfig.configuration setValue:[NSDictionary dictionaryWithObjectsAndKeys:[endpointUrl absoluteString],BaseUrl, nil] forKey:key];
}
}
NSAssert([SINGLETON_PNObjectConfig.configuration objectForKey:EnvironmentProduction], @"EnvironmentProduction must be valid endpoint url");
}
});
return SINGLETON_PNObjectConfig;
}
+ (id) allocWithZone:(NSZone *)zone
{
return [self sharedInstance];
}
+ (id)copyWithZone:(struct _NSZone *)zone
{
return [self sharedInstance];
}
+ (id)mutableCopyWithZone:(struct _NSZone *)zone
{
return [self sharedInstance];
}
- (id)copy
{
return [[PNObjectConfig alloc] init];
}
- (id)mutableCopy
{
return [[PNObjectConfig alloc] init];
}
- (id) initWithUserSubclass:(Class _Nonnull) userSubClass withOauth:(BOOL) oauthEnabled
{
if(SINGLETON_PNObjectConfig){
return SINGLETON_PNObjectConfig;
}
if (isFirstAccess) {
[self doesNotRecognizeSelector:_cmd];
}
self = [super init];
if (self) {
_oauthEnabled = oauthEnabled;
_userSubClass = userSubClass;
_configuration = [[NSMutableDictionary alloc] init];
_minPasswordLenght = minPassLenght;
_currentEnv = EnvironmentProduction;
_jsonSerializer = [AFJSONRequestSerializer serializer];
_httpSerializer = [AFHTTPRequestSerializer serializer];
_headerFields = [[NSMutableDictionary alloc] init];
if(![DDDKeychainWrapper dataForKey:PNObjectEncryptionKey]){
NSData *key = [NARandom randomData:NASecretBoxKeySize];
NSData *nonce = [NARandom randomData:NASecretBoxNonceSize];
[DDDKeychainWrapper setData:key forKey:PNObjectEncryptionKey];
[DDDKeychainWrapper setData:nonce forKey:PNObjectEncryptionNonce];
}
if (_oauthEnabled) {
AFOAuthCredential *clientCredential = [AFOAuthCredential retrieveCredentialWithIdentifier:PNObjectServiceClientCredentialIdentifier];
if (clientCredential) {
_currentOauthCredential = clientCredential;
}
AFOAuthCredential *userCredential = [AFOAuthCredential retrieveCredentialWithIdentifier:PNObjectServiceUserCredentialIdentifier];
if (userCredential) {
_currentOauthCredential = userCredential;
}
}
}
return self;
}
- (void) setEnvironment:(NSString * _Nonnull) environment {
_currentEnv = environment;
_currentEndPointBaseUrl = nil;
_currentOAuthClientID = nil;
_currentOAuthClientSecret = nil;
if ([_configuration objectForKey:environment]) {
_currentEndPointBaseUrl = [[_configuration objectForKey:_currentEnv] objectForKey:BaseUrl];
_currentOAuthClientID = [[_configuration objectForKey:_currentEnv] objectForKey:Client_ID];
_currentOAuthClientSecret = [[_configuration objectForKey:_currentEnv] objectForKey:Client_Secret];
}
NSLogDebug(@"%@",[[_configuration objectForKey:_currentEnv] objectForKey:BaseUrl]);
NSAssert(_currentEndPointBaseUrl,@"Selected environment generate error. Please check configuration");
if (_currentOAuthClientID && _currentOAuthClientSecret) {
[self authManager];
[self manager];
}
}
- (NSString *) baseUrl {
return _currentEndPointBaseUrl;
}
- (AFHTTPSessionManager *) manager {
if (!_manager) {
_manager = [AFHTTPSessionManager manager];
for (NSString *key in [_headerFields allKeys]) {
[_httpSerializer setValue:[_headerFields objectForKey:key] forHTTPHeaderField:key];
[_jsonSerializer setValue:[_headerFields objectForKey:key] forHTTPHeaderField:key];
}
if (_currentOauthCredential && ![_currentOauthCredential isExpired] && ![[_manager requestSerializer] hasAuthorizationHeaderField]) {
[_httpSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_jsonSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_manager.requestSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
}
else {
[self refreshToken];
}
_manager.responseSerializer = [AFJSONResponseSerializerWithData serializer];
_manager.requestSerializer = _jsonSerializer;
}
return _manager;
}
- (AFOAuth2Manager *) authManager {
BOOL canTryRefreh = NO;
if (!_authManager) {
_authManager = [AFOAuth2Manager manager];
if (_oauthEnabled && _currentOAuthClientID && _currentOAuthClientSecret) {
if (![_authManager clientID]) {
_authManager = [AFOAuth2Manager managerWithBaseURL:[NSURL URLWithString:_currentEndPointBaseUrl] clientID:_currentOAuthClientID secret:_currentOAuthClientSecret];
}
[_authManager setUseHTTPBasicAuthentication:NO];
canTryRefreh = YES;
}
for (NSString *key in [_headerFields allKeys]) {
[_httpSerializer setValue:[_headerFields objectForKey:key] forHTTPHeaderField:key];
[_jsonSerializer setValue:[_headerFields objectForKey:key] forHTTPHeaderField:key];
}
if (canTryRefreh) {
if (_currentOauthCredential && ![_currentOauthCredential isExpired] && ![[_manager requestSerializer] hasAuthorizationHeaderField]) {
[_httpSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_jsonSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_authManager.requestSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
}
else {
[self refreshToken];
}
}
_authManager.responseSerializer = [AFJSONResponseSerializerWithData serializer];
}
return _authManager;
}
- (BOOL) resetToken {
if (_currentOauthCredential) {
_currentOauthCredential = nil;
[AFOAuthCredential deleteCredentialWithIdentifier:PNObjectServiceClientCredentialIdentifier];
return [AFOAuthCredential deleteCredentialWithIdentifier:PNObjectServiceUserCredentialIdentifier];
}
return NO;
}
- (void) refreshToken {
[self refreshTokenWithBlockSuccess:nil failure:nil];
}
- (void) refreshTokenWithBlockSuccess:(nullable void (^)(BOOL refreshSuccess))success
failure:(nullable void (^)(NSError * _Nonnull error))failure {
if([SINGLETON_PNObjectConfig.userSubClass currentUser] && ([[SINGLETON_PNObjectConfig.userSubClass currentUser] hasValidEmailAndPasswordData] || [[SINGLETON_PNObjectConfig.userSubClass currentUser] facebookId])) {
[self refreshTokenForUserWithBlockSuccess:success failure:failure];
}
else {
[self refreshTokenForClientCredentialWithBlockSuccess:success failure:failure];
}
}
- (void) refreshTokenForUser {
[self refreshTokenForUserWithBlockSuccess:nil failure:nil];
}
- (void) refreshTokenForUserWithBlockSuccess:(nullable void (^)(BOOL refreshSuccess))success
failure:(nullable void (^)(NSError * _Nonnull error))failure {
if (_currentOauthCredential) {
[_authManager authenticateUsingOAuthWithURLString:[_currentEndPointBaseUrl stringByAppendingString:@"oauth-token"] refreshToken:[_currentOauthCredential refreshToken] success:^(AFOAuthCredential * _Nonnull credential) {
_currentOauthCredential = credential;
[AFOAuthCredential storeCredential:_currentOauthCredential withIdentifier:PNObjectServiceUserCredentialIdentifier];
[_httpSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_jsonSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_authManager.requestSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_manager.requestSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[[NSNotificationCenter defaultCenter] postNotificationName:PNObjectLocalNotificationRefreshTokenUserSuccess object:nil];
if (success) {
success(YES);
}
return;
} failure:^(NSError * _Nonnull error) {
[self resetToken];
[self refreshTokenForUserWithBlockSuccess:success failure:failure];
return;
}];
}
else {
if([SINGLETON_PNObjectConfig.userSubClass currentUser] && [[SINGLETON_PNObjectConfig.userSubClass currentUser] hasValidEmailAndPasswordData]) {
[self refreshTokenForUserWithEmail:[[SINGLETON_PNObjectConfig.userSubClass currentUser] email] password:[[(PNUser*)[SINGLETON_PNObjectConfig.userSubClass currentUser] password] password] withBlockSuccess:success failure:failure];
return;
}
else if ([SINGLETON_PNObjectConfig.userSubClass currentUser] && [[SINGLETON_PNObjectConfig.userSubClass currentUser] facebookId]){
[FBSDKAccessToken refreshCurrentAccessToken:^(FBSDKGraphRequestConnection *connection, id result, NSError *error) {
if (error) {
if (failure) {
failure(error);
}
}
else {
[self refreshTokenForUserWithFacebookID:[[SINGLETON_PNObjectConfig.userSubClass currentUser] facebookId] facebookToken:[[FBSDKAccessToken currentAccessToken] tokenString] withBlockSuccess:success failure:failure];
}
}];
}
else {
if (failure) {
NSError *error = [NSError errorWithDomain:@"" code:kHTTPStatusCodeBadRequest userInfo:nil];
failure(error);
[[NSNotificationCenter defaultCenter] postNotificationName:PNObjectLocalNotificationRefreshTokenUserFail object:nil];
}
}
}
}
- (void) refreshTokenForUserWithEmail:(NSString * _Nonnull) email
password:(NSString * _Nonnull) password
withBlockSuccess:(nullable void (^)(BOOL refreshSuccess))success
failure:(nullable void (^)(NSError * _Nonnull error))failure {
if (![email isValidEmail]) {
if (failure) {
NSError *error = [NSError errorWithDomain:NSLocalizedString(@"Email is not valid", @"") code:kHTTPStatusCodeBadRequest userInfo:nil];
failure(error);
return;
}
}
if (![SINGLETON_PNObjectConfig.userSubClass isValidPassword:password]) {
if (failure) {
NSError *error = [NSError errorWithDomain:NSLocalizedString(@"Password is not valid", @"") code:kHTTPStatusCodeBadRequest userInfo:nil];
failure(error);
return;
}
}
[_authManager authenticateUsingOAuthWithURLString:[_currentEndPointBaseUrl stringByAppendingString:@"oauth-token"] username:email password:password scope:nil success:^(AFOAuthCredential * _Nonnull credential) {
_currentOauthCredential = credential;
[AFOAuthCredential storeCredential:_currentOauthCredential withIdentifier:PNObjectServiceUserCredentialIdentifier];
[_httpSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_jsonSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_authManager.requestSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_manager.requestSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[[NSNotificationCenter defaultCenter] postNotificationName:PNObjectLocalNotificationRefreshTokenUserSuccess object:nil];
if (success) {
success(YES);
}
} failure:^(NSError * _Nonnull error) {
[[NSNotificationCenter defaultCenter] postNotificationName:PNObjectLocalNotificationRefreshTokenUserFail object:nil];
if (failure) {
failure(error);
}
}];
}
- (void) refreshTokenForUserWithFacebookID:(NSString * _Nonnull) facebookID
facebookToken:(NSString * _Nonnull) facebookToken
withBlockSuccess:(nullable void (^)(BOOL refreshSuccess))success
failure:(nullable void (^)(NSError * _Nonnull error))failure {
if (!facebookID || [facebookID length] == 0) {
if (failure) {
NSError *error = [NSError errorWithDomain:NSLocalizedString(@"Facebook id is not valid", @"") code:kHTTPStatusCodeBadRequest userInfo:nil];
failure(error);
return;
}
}
if (!facebookToken || [facebookToken length] == 0) {
if (failure) {
NSError *error = [NSError errorWithDomain:NSLocalizedString(@"Facebook token is not valid", @"") code:kHTTPStatusCodeBadRequest userInfo:nil];
failure(error);
return;
}
}
[_authManager authenticateUsingFacebookOAuthWithURLString:[_currentEndPointBaseUrl stringByAppendingString:@"oauth-token"] facebookID:facebookID facebookToken:facebookToken scope:nil success:^(AFOAuthCredential * _Nonnull credential) {
_currentOauthCredential = credential;
[AFOAuthCredential storeCredential:_currentOauthCredential withIdentifier:PNObjectServiceUserCredentialIdentifier];
[_httpSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_jsonSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_authManager.requestSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_manager.requestSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[[NSNotificationCenter defaultCenter] postNotificationName:PNObjectLocalNotificationRefreshTokenUserSuccess object:nil];
if (success) {
success(YES);
}
} failure:^(NSError * _Nonnull error) {
[[NSNotificationCenter defaultCenter] postNotificationName:PNObjectLocalNotificationRefreshTokenUserFail object:nil];
if (failure) {
failure(error);
}
}];
}
- (void) refreshTokenForClientCredential {
[self refreshTokenForClientCredentialWithBlockSuccess:nil failure:nil];
}
- (void) refreshTokenForClientCredentialWithBlockSuccess:(nullable void (^)(BOOL refreshSuccess))success
failure:(nullable void (^)(NSError * _Nonnull error))failure {
if (_currentOauthCredential) {
[_authManager authenticateUsingOAuthWithURLString:[_currentEndPointBaseUrl stringByAppendingString:@"oauth-token"] refreshToken:[_currentOauthCredential refreshToken] success:^(AFOAuthCredential * _Nonnull credential) {
_currentOauthCredential = credential;
[AFOAuthCredential storeCredential:_currentOauthCredential withIdentifier:PNObjectServiceClientCredentialIdentifier];
[_httpSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_jsonSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_authManager.requestSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_manager.requestSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[[NSNotificationCenter defaultCenter] postNotificationName:PNObjectLocalNotificationRefreshTokenClientCredentialSuccess object:nil];
if (success) {
success(YES);
}
return;
} failure:^(NSError * _Nonnull error) {
[self resetToken];
[self refreshTokenForClientCredentialWithBlockSuccess:success failure:failure];
return;
}];
}
else {
[_authManager authenticateUsingOAuthWithURLString:[_currentEndPointBaseUrl stringByAppendingString:@"oauth-token"] scope:nil success:^(AFOAuthCredential * _Nonnull credential) {
_currentOauthCredential = credential;
[AFOAuthCredential storeCredential:_currentOauthCredential withIdentifier:PNObjectServiceClientCredentialIdentifier];
[_httpSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_jsonSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_authManager.requestSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[_manager.requestSerializer setAuthorizationHeaderFieldWithCredential:_currentOauthCredential];
[[NSNotificationCenter defaultCenter] postNotificationName:PNObjectLocalNotificationRefreshTokenClientCredentialSuccess object:nil];
if (success) {
success(YES);
}
} failure:^(NSError * _Nonnull error) {
[[NSNotificationCenter defaultCenter] postNotificationName:PNObjectLocalNotificationRefreshTokenClientCredentialFail object:nil];
if (failure) {
failure(error);
}
}];
}
}
- (void) setAcceptablePasswordLenght:(NSUInteger) passLenght {
_minPasswordLenght = passLenght;
}
- (void) setHTTPHeaderValue:(NSString * _Nonnull)value forKey:(NSString * _Nonnull) key {
[_headerFields setObject:value forKey:key];
}
- (void) removeHTTPHeaderValueForKey:(NSString * _Nonnull) key {
if ([_headerFields objectForKey:key]) {
[_headerFields removeObjectForKey:key];
}
}
- (void) setClientID:(NSString * _Nonnull) clientID clientSecret:(NSString* _Nonnull) clientSecret forEnv:(NSString *) environment {
if ([_configuration objectForKey:environment]) {
NSMutableDictionary *currentConfigurationDict = [[NSMutableDictionary alloc] initWithDictionary:[_configuration objectForKey:environment]];
[currentConfigurationDict setObject:clientID forKey:Client_ID];
[currentConfigurationDict setObject:clientSecret forKey:Client_Secret];
[_configuration setObject:currentConfigurationDict forKey:environment];
if (_currentEnv == environment) {
[self setEnvironment:environment];
}
}
}
@end
+31
View File
@@ -0,0 +1,31 @@
//
// PNObjectConstants.h
// Pods
//
// Created by Giuseppe Nucifora on 16/01/16.
//
//
#ifndef PNObjectConstants_h
#define PNObjectConstants_h
#pragma mark Constants
#define DEF_DOCUMENT_ROOT @"Documents"
#pragma mark -
#pragma mark NSLogDebug Macro
#define FORCE_NO_LOG 0
#if defined(FORCE_NO_LOG) && FORCE_NO_LOG == 0
#define NSLogDebug(format, ...) NSLog(@"<%s:%d> %s, " format, strrchr("/" __FILE__, '/') + 1, __LINE__, __PRETTY_FUNCTION__, ## __VA_ARGS__)
#else
#define NSLogDebug(format, ...)
#endif
#define VariableName(arg) ([[[@""#arg stringByReplacingOccurrencesOfString:@"_" withString:@""] componentsSeparatedByString:@"."] lastObject])
#endif
+54
View File
@@ -0,0 +1,54 @@
//
// PNObjectFormData.h
// Pods
//
// Created by Giuseppe Nucifora on 16/02/16.
//
//
#import <Foundation/Foundation.h>
@interface PNObjectFormData : NSObject
@property (nonatomic, strong, nonnull) NSData *formData;
@property (nonatomic, strong, nonnull) NSString * name;
@property (nonatomic, strong, nonnull) NSString * fileName;
@property (nonatomic, strong, nonnull) NSString * mimeType;
/**
* <#Description#>
*
* @param formData <#formData description#>
* @param name <#name description#>
* @param fileName <#fileName description#>
* @param mimeType <#mimeType description#>
*
* @return <#return value description#>
*/
+ (instancetype _Nonnull) formDataFromNSData:(NSData * _Nonnull) formData name:(NSString * _Nonnull) name fileName:(NSString * _Nonnull) fileName mimeType:(NSString * _Nonnull) mimeType;
/**
* <#Description#>
*
* @param image <#image description#>
* @param name <#name description#>
* @param fileName <#fileName description#>
* @param mimeType <#mimeType description#>
*
* @return <#return value description#>
*/
+ (instancetype _Nonnull) formDataFromUIImage:(UIImage * _Nonnull) image name:(NSString * _Nonnull) name fileName:(NSString * _Nonnull) fileName mimeType:(NSString * _Nonnull) mimeType;
/**
* <#Description#>
*
* @param image <#image description#>
* @param compression <#compression description#>
* @param name <#name description#>
* @param fileName <#fileName description#>
* @param mimeType <#mimeType description#>
*
* @return <#return value description#>
*/
+ (instancetype _Nonnull) formDataFromUIImage:(UIImage * _Nonnull) image compression:(CGFloat) compression name:(NSString * _Nonnull) name fileName:(NSString * _Nonnull) fileName mimeType:(NSString * _Nonnull) mimeType;
@end
+40
View File
@@ -0,0 +1,40 @@
//
// PNObjectFormData.m
// Pods
//
// Created by Giuseppe Nucifora on 16/02/16.
//
//
#import "PNObjectFormData.h"
@implementation PNObjectFormData
+ (instancetype _Nonnull) formDataFromNSData:(NSData * _Nonnull) formData name:(NSString * _Nonnull) name fileName:(NSString * _Nonnull) fileName mimeType:(NSString * _Nonnull) mimeType {
PNObjectFormData * responseData = [PNObjectFormData new];
[responseData setFormData:formData];
[responseData setName:name];
[responseData setFileName:fileName];
[responseData setMimeType:mimeType];
return responseData;
}
+ (instancetype _Nonnull) formDataFromUIImage:(UIImage * _Nonnull) image name:(NSString * _Nonnull) name fileName:(NSString * _Nonnull) fileName mimeType:(NSString * _Nonnull) mimeType {
return [self formDataFromUIImage:image compression:1 name:name fileName:fileName mimeType:mimeType];
}
+ (instancetype _Nonnull) formDataFromUIImage:(UIImage * _Nonnull) image compression:(CGFloat) compression name:(NSString * _Nonnull) name fileName:(NSString * _Nonnull) fileName mimeType:(NSString * _Nonnull) mimeType {
PNObjectFormData * responseData = [PNObjectFormData new];
[responseData setFormData:UIImageJPEGRepresentation(image, compression)];
[responseData setName:name];
[responseData setFileName:fileName];
[responseData setMimeType:mimeType];
return responseData;
}
@end
+55
View File
@@ -0,0 +1,55 @@
//
// PNObjectModel.h
// Pods
//
// Created by Giuseppe Nucifora on 16/01/16.
//
//
#import <Foundation/Foundation.h>
@protocol PNObjectPersistency <NSObject>
@required
- (BOOL) initObjectPersistency;
@end
@interface PNObjectModel : NSObject
@property (nonatomic, assign, nonnull) id<PNObjectPersistency> persistencyDelegate;
+ (_Nonnull instancetype) sharedInstance;
/**
* <#Description#>
*
* @param class <#class description#>
*
* @return <#return value description#>
*/
- (id _Nonnull) fetchObjectsWithClass:(Class _Nonnull) class;
/**
* <#Description#>
*
* @param object PNObject Subclass to save
*
* @return return It return the object if the save was successful.
* @return return NSError
*/
- (id _Nonnull) saveLocally:(id _Nonnull) object;
/**
* <#Description#>
*
* @param object PNObject Subclass add list objects and save the list
*
* @return <#return value description#>
*/
- (BOOL) removeObjectLocally:(id _Nonnull) object;
@end
+272
View File
@@ -0,0 +1,272 @@
//
// PNObjectModel.m
// Pods
//
// Created by Giuseppe Nucifora on 16/01/16.
//
//
#import "PNObjectModel.h"
#import "PNObject+Protected.h"
#import "PEARFileManager.h"
#import "PNObjectConstants.h"
#import <DDDKeychainWrapper/DDDKeychainWrapper.h>
#import <NAChloride/NAChloride.h>
#import "HTTPStatusCodes.h"
@interface PNObjectModel()
@property (nonatomic, strong) PEARFileManager *fileManager;
@property (nonatomic, strong) NASecretBox *secretBox;
@end
@implementation PNObjectModel
static PNObjectModel *SINGLETON_PNObjectModel = nil;
static bool isFirstAccess = YES;
#pragma mark Public Method
+ (instancetype) sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
isFirstAccess = NO;
SINGLETON_PNObjectModel = [[super allocWithZone:NULL] init];
});
return SINGLETON_PNObjectModel;
}
- (NSString * _Nullable) objectName:(id _Nonnull) object {
BOOL isPNObjectSubclass = [[object class] isSubclassOfClass:[PNObject class]];
if(isPNObjectSubclass) {
if ([[object class] conformsToProtocol:@protocol(PNObjectSubclassing)]) {
NSString *className;
//if ([[object subClassDelegate] respondsToSelector:@selector(objectClassName)]) {
@try {
className = (NSString *)[[object class] performSelector:@selector(objectClassName)];
}
@catch (NSException *exception) {
return nil;
}
@finally {
return className;
}
//}
}
}
return nil;
}
- (BOOL) issetPNObjectModelForObject:(id _Nonnull) object {
NSString *className = [self objectName:object];
if (!className) {
return NO;
}
return [_fileManager checkPath:className];
}
#pragma mark -
+ (id) allocWithZone:(NSZone *)zone
{
return [self sharedInstance];
}
+ (id)copyWithZone:(struct _NSZone *)zone
{
return [self sharedInstance];
}
+ (id)mutableCopyWithZone:(struct _NSZone *)zone
{
return [self sharedInstance];
}
- (id)copy
{
return [[PNObjectModel alloc] init];
}
- (id)mutableCopy
{
return [[PNObjectModel alloc] init];
}
- (id) init
{
if(SINGLETON_PNObjectModel){
return SINGLETON_PNObjectModel;
}
if (isFirstAccess) {
[self doesNotRecognizeSelector:_cmd];
}
self = [super init];
if (self) {
_fileManager = [PEARFileManager sharedInstatnce];
[_fileManager setRootDirectory:k_ROOT_DIR_DOCUMENTS];
NSLogDebug(@"%@",[_fileManager getRootDirectoryPath]);
_secretBox = [[NASecretBox alloc] init];
}
return self;
}
#pragma mark Public Methods
- (id _Nonnull) fetchObjectsWithClass:(Class _Nonnull) class {
BOOL isPNObjectSubclass = [class isSubclassOfClass:[PNObject class]];
if(isPNObjectSubclass) {
NSString *className;
@try {
className = (NSString *)[class performSelector:@selector(objectClassName)];
}
@catch (NSException *exception) {
}
@finally {
if ([_fileManager checkPath:className]) {
NSError *error = nil;
NSData *data = [_secretBox decrypt:[_fileManager fetchFileDataWithPath:className] nonce:[DDDKeychainWrapper dataForKey:PNObjectEncryptionNonce] key:[DDDKeychainWrapper dataForKey: PNObjectEncryptionKey] error:&error]; // password:[[PNObjectConfig sharedInstance] encrypKey] error:&error];
return [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
else
return nil;
}
}
}
- (id _Nonnull) saveLocally:(id _Nonnull) object {
BOOL isPNObjectSubclass = [[object class] isSubclassOfClass:[PNObject class]];
NSError *error = nil;
if(isPNObjectSubclass) {
if ([[object class] conformsToProtocol:@protocol(PNObjectSubclassing)]) {
if ([(PNObject*) object singleInstance]) {
NSDictionary *objectDict = [(PNObject*) object reverseMapping];
NSData *objectData = [_secretBox encrypt:[NSKeyedArchiver archivedDataWithRootObject:objectDict] nonce:[DDDKeychainWrapper dataForKey: PNObjectEncryptionNonce] key:[DDDKeychainWrapper dataForKey: PNObjectEncryptionKey] error:&error];//[RNCryptor encryptData:[NSKeyedArchiver archivedDataWithRootObject:objectDict] password:[[PNObjectConfig sharedInstance] encrypKey]];
if ([self issetPNObjectModelForObject:object]) {
if ([_fileManager updateFileWithData:objectData filePath:[self objectName:object] permisson:@(0755)]) {
return object;
}
else {
return [NSError errorWithDomain:NSLocalizedString(@"Object cannot be updated", @"") code:kHTTPStatusCodeBadRequest userInfo:nil];
}
}
else {
if ([_fileManager createFileWithData:objectData filePath:[self objectName:object] permisson:@(0755)]) {
return object;
}
else {
return [NSError errorWithDomain:NSLocalizedString(@"Object cannot be created", @"") code:kHTTPStatusCodeBadRequest userInfo:nil];
}
}
}
else {
if ([self issetPNObjectModelForObject:object]) {
//NSData * data = [_fileManager fetchFileDataWithPath:[self objectName:object]];
NSData *data = [_secretBox decrypt:[_fileManager fetchFileDataWithPath:[self objectName:object]] nonce:[DDDKeychainWrapper dataForKey: PNObjectEncryptionNonce] key:[DDDKeychainWrapper dataForKey: PNObjectEncryptionKey] error:&error];
//[RNCryptor decryptData:[_fileManager fetchFileDataWithPath:[self objectName:object]] password:[[PNObjectConfig sharedInstance] encrypKey] error:&error];
NSMutableArray *objects = [[NSMutableArray alloc] initWithArray:[NSKeyedUnarchiver unarchiveObjectWithData:data]];
NSDictionary *objectDict = [(PNObject*)object reverseMapping];
[objects addObject:objectDict];
NSData *objectData = [_secretBox encrypt:[NSKeyedArchiver archivedDataWithRootObject:objects] nonce:[DDDKeychainWrapper dataForKey: PNObjectEncryptionNonce] key:[DDDKeychainWrapper dataForKey:PNObjectEncryptionKey] error:&error];
//[RNCryptor encryptData:[NSKeyedArchiver archivedDataWithRootObject:objects] password:[[PNObjectConfig sharedInstance] encrypKey]];
if ([_fileManager updateFileWithData:objectData filePath:[self objectName:object] permisson:@(0755)]) {
return objects;
}
else {
return [NSError errorWithDomain:NSLocalizedString(@"Objects list cannot be updated", @"") code:kHTTPStatusCodeBadRequest userInfo:nil];
}
}
else {
NSMutableArray *objects = [[NSMutableArray alloc] init];
NSDictionary *objectDict = [(PNObject*)object reverseMapping];
[objects addObject:objectDict];
NSData *objectData = [_secretBox encrypt:[NSKeyedArchiver archivedDataWithRootObject:objects] nonce:[DDDKeychainWrapper dataForKey:PNObjectEncryptionNonce] key:[DDDKeychainWrapper dataForKey:PNObjectEncryptionKey] error:&error];
//[RNCryptor encryptData:[NSKeyedArchiver archivedDataWithRootObject:objects] password:[[PNObjectConfig sharedInstance] encrypKey]];
if ([_fileManager createFileWithData:objectData filePath:[self objectName:object] permisson:@(0755)]) {
return object;
}
else {
return [NSError errorWithDomain:NSLocalizedString(@"Objects list cannot be created", @"") code:kHTTPStatusCodeBadRequest userInfo:nil];
}
}
}
}
else {
return [NSError errorWithDomain:NSLocalizedString(@"passed object is not conform to protocol PNObjectSubclassing", @"") code:kHTTPStatusCodeBadRequest userInfo:nil];
}
}
else {
return [NSError errorWithDomain:NSLocalizedString(@"passed object is not PNObject Subclass", @"") code:kHTTPStatusCodeBadRequest userInfo:nil];
}
}
/*- (id _Nonnull) saveNSUSerDefautls:(id _Nonnull) object {
}*/
- (BOOL) removeObjectLocally:(id _Nonnull) object {
BOOL isPNObjectSubclass = [[object class] isSubclassOfClass:[PNObject class]];
if(isPNObjectSubclass) {
if ([[object class] conformsToProtocol:@protocol(PNObjectSubclassing)]) {
if ([self issetPNObjectModelForObject:object]) {
return [_fileManager deletePath:[self objectName:object]];
}
}
}
return NO;
}
@end
+15
View File
@@ -0,0 +1,15 @@
//
// PNObjectUtilities.h
// Pods
//
// Created by Giuseppe Nucifora on 17/03/16.
//
//
#import <Foundation/Foundation.h>
@interface PNObjectUtilities : NSObject
+ (UIViewController *) topViewController;
@end
+33
View File
@@ -0,0 +1,33 @@
//
// PNObjectUtilities.m
// Pods
//
// Created by Giuseppe Nucifora on 17/03/16.
//
//
#import "PNObjectUtilities.h"
@implementation PNObjectUtilities
+ (UIViewController *)topViewController {
return [self topViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
+ (UIViewController *)topViewController:(UIViewController *)rootViewController
{
if (rootViewController.presentedViewController == nil) {
return rootViewController;
}
if ([rootViewController.presentedViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController;
UIViewController *lastViewController = [[navigationController viewControllers] lastObject];
return [self topViewController:lastViewController];
}
UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController;
return [self topViewController:presentedViewController];
}
@end
@@ -0,0 +1,15 @@
//
// AFJSONResponseSerializerWithData.h
// Pods
//
// Created by Giuseppe Nucifora on 08/02/16.
//
//
#import <AFNetworking/AFNetworking.h>
static NSString * const JSONResponseSerializerWithDataKey = @"JSONResponseSerializerWithDataKey";
@interface AFJSONResponseSerializerWithData : AFJSONResponseSerializer
@end
@@ -0,0 +1,31 @@
//
// AFJSONResponseSerializerWithData.m
// Pods
//
// Created by Giuseppe Nucifora on 08/02/16.
//
//
#import "AFJSONResponseSerializerWithData.h"
@implementation AFJSONResponseSerializerWithData
- (id)responseObjectForResponse:(NSURLResponse *)response
data:(NSData *)data
error:(NSError *__autoreleasing *)error
{
id JSONObject = [super responseObjectForResponse:response data:data error:error];
NSHTTPURLResponse *currentResponse = (NSHTTPURLResponse*)response;
if (*error != nil) {
NSData *errorData = [[(*error).userInfo mutableCopy] objectForKey:AFNetworkingOperationFailingURLResponseDataErrorKey];
NSMutableDictionary *userInfo = [NSJSONSerialization JSONObjectWithData: errorData options:kNilOptions error:nil];;
NSError *newError = [NSError errorWithDomain:(*error).domain code:currentResponse.statusCode userInfo:userInfo];
(*error) = newError;
}
return (JSONObject);
}
@end
@@ -0,0 +1,38 @@
// AFHTTPRequestSerializer+OAuth2.h
//
// Copyright (c) 2012-2014 AFNetworking (http://afnetworking.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 <AFNetworking/AFURLRequestSerialization.h>
@class AFOAuthCredential;
@interface AFHTTPRequestSerializer (OAuth2)
/**
Sets the "Authorization" HTTP header set in request objects made by the HTTP client to contain the access token within the OAuth credential. This overwrites any existing value for this header.
@param credential The OAuth2 credential
*/
- (void)setAuthorizationHeaderFieldWithCredential:(AFOAuthCredential *)credential;
- (BOOL) hasAuthorizationHeaderField;
@end
@@ -0,0 +1,44 @@
// AFHTTPRequestSerializer+OAuth2.m
//
// Copyright (c) 2012-2014 AFNetworking (http://afnetworking.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 "AFHTTPRequestSerializer+OAuth2.h"
#import "AFOAuth2Manager.h"
#import "AFOAuthCredential.h"
@implementation AFHTTPRequestSerializer (OAuth2)
- (void)setAuthorizationHeaderFieldWithCredential:(AFOAuthCredential *)credential {
if ([credential.tokenType compare:@"Bearer" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
[self setValue:[NSString stringWithFormat:@"Bearer %@", credential.accessToken] forHTTPHeaderField:@"Authorization"];
}
}
- (BOOL) hasAuthorizationHeaderField {
NSString *token = [self valueForHTTPHeaderField:@"Authorization"];
if ([token containsString:@"Bearer"]) {
return YES;
}
return NO;
}
@end
@@ -0,0 +1,208 @@
// AFOAuth2Manager.h
//
// Copyright (c) 2012-2014 AFNetworking (http://afnetworking.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 <Foundation/Foundation.h>
#import <AFNetworking/AFNetworking.h>
#import "AFOAuthCredential.h"
#import "AFHTTPRequestSerializer+OAuth2.h"
NS_ASSUME_NONNULL_BEGIN
@interface AFOAuth2Manager : AFHTTPSessionManager
///------------------------------------------
/// @name Accessing OAuth 2 Client Properties
///------------------------------------------
/**
The service provider identifier used to store and retrieve OAuth credentials by `AFOAuthCredential`. Equivalent to the hostname of the client `baseURL`.
*/
@property (readonly, nonatomic, copy) NSString *serviceProviderIdentifier;
/**
The client identifier issued by the authorization server, uniquely representing the registration information provided by the client.
*/
@property (readonly, nonatomic, copy) NSString *clientID;
/**
Whether to encode client credentials in a Base64-encoded HTTP `Authorization` header, as opposed to the request body. Defaults to `YES`.
*/
@property (nonatomic, assign) BOOL useHTTPBasicAuthentication;
///------------------------------------------------
/// @name Creating and Initializing OAuth 2 Managers
///------------------------------------------------
/**
Creates and initializes an `AFOAuth2Manager` object with the specified base URL, client identifier, and secret.
@param url The base URL for the HTTP client. This argument must not be `nil`.
@param clientID The client identifier issued by the authorization server, uniquely representing the registration information provided by the client. This argument must not be `nil`.
@param secret The client secret.
@return The newly-initialized OAuth 2 manager
*/
+ (instancetype)managerWithBaseURL:(NSURL *)url
clientID:(NSString *)clientID
secret:(NSString *)secret;
+ (instancetype)managerWithBaseURL:(NSURL *)url
sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration
clientID:(NSString *)clientID
secret:(NSString *)secret;
/**
Initializes an `AFOAuth2Manager` object with the specified base URL, client identifier, and secret. The communication to to the server will use HTTP basic auth by default (use `-(id)initWithBaseURL:clientID:secret:withBasicAuth:` to change this).
@param url The base URL for the HTTP manager. This argument must not be `nil`.
@param clientID The client identifier issued by the authorization server, uniquely representing the registration information provided by the client. This argument must not be `nil`.
@param secret The client secret.
@return The newly-initialized OAuth 2 client
*/
- (id)initWithBaseURL:(NSURL *)url
clientID:(NSString *)clientID
secret:(NSString *)secret;
- (id)initWithBaseURL:(NSURL *)url
sessionConfiguration:(nullable NSURLSessionConfiguration *)configuration
clientID:(NSString *)clientID
secret:(NSString *)secret;
///---------------------
/// @name Authenticating
///---------------------
/**
Creates and enqueues an `NSURLSessionTask` to authenticate against the server using a specified username and password, with a designated scope.
@param URLString The URL string used to create the request URL.
@param username The username used for authentication
@param password The password used for authentication
@param scope The authorization scope
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes a single argument: the OAuth credential returned by the server.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error returned from the server.
*/
- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString
username:(NSString *)username
password:(NSString *)password
scope:(nullable NSString *)scope
success:(void (^)(AFOAuthCredential *credential))success
failure:(void (^)(NSError *error))failure;
/**
Creates and enqueues an `NSURLSessionTask` to authenticate against the server using a specified facebook id and facebook token, with a designated scope.
@param URLString The URL string used to create the request URL.
@param facebookID The facebook id used for authentication
@param facebookToken The facebook token used for authentication
@param scope The authorization scope
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes a single argument: the OAuth credential returned by the server.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error returned from the server.
*/
- (NSURLSessionTask *)authenticateUsingFacebookOAuthWithURLString:(NSString *)URLString
facebookID:(NSString *)facebookid
facebookToken:(NSString *)facebookToken
scope:(nullable NSString *)scope
success:(void (^)(AFOAuthCredential * _Nonnull))success
failure:(void (^)(NSError * _Nonnull))failure;
/**
Creates and enqueues an `NSURLSessionTask` to authenticate against the server with a designated scope.
@param URLString The URL string used to create the request URL.
@param scope The authorization scope
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes a single argument: the OAuth credential returned by the server.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error returned from the server.
*/
- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString
scope:(nullable NSString *)scope
success:(void (^)(AFOAuthCredential *credential))success
failure:(void (^)(NSError *error))failure;
/**
Creates and enqueues an `NSURLSessionTask` to authenticate against the server using the specified refresh token.
@param URLString The URL string used to create the request URL.
@param refreshToken The OAuth refresh token
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes a single argument: the OAuth credential returned by the server.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error returned from the server.
*/
- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString
refreshToken:(NSString *)refreshToken
success:(void (^)(AFOAuthCredential *credential))success
failure:(void (^)(NSError *error))failure;
/**
Creates and enqueues an `NSURLSessionTask` to authenticate against the server with an authorization code, redirecting to a specified URI upon successful authentication.
@param URLString The URL string used to create the request URL.
@param code The authorization code
@param uri The URI to redirect to after successful authentication
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes a single argument: the OAuth credential returned by the server.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error returned from the server.
*/
- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString
code:(NSString *)code
redirectURI:(NSString *)uri
success:(void (^)(AFOAuthCredential *credential))success
failure:(void (^)(NSError *error))failure;
/**
Creates and enqueues an `NSURLSessionTask` to authenticate against the server with the specified parameters.
@param URLString The URL string used to create the request URL.
@param parameters The parameters to be encoded and set in the request HTTP body.
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes a single argument: the OAuth credential returned by the server.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error returned from the server.
*/
- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString
parameters:(NSDictionary *)parameters
success:(void (^)(AFOAuthCredential *credential))success
failure:(void (^)(NSError *error))failure;
@end
///----------------
/// @name Constants
///----------------
/**
## Error Domains
The following error domain is predefined.
- `NSString * const AFOAuth2ErrorDomain`
## OAuth Grant Types
OAuth 2.0 provides several grant types, covering several different use cases. The following grant type string constants are provided:
`kAFOAuthCodeGrantType`: "authorization_code"
`kAFOAuthClientCredentialsGrantType`: "client_credentials"
`kAFOAuthPasswordCredentialsGrantType`: "password"
`kAFOAuthRefreshGrantType`: "refresh_token"
*/
extern NSString * const AFOAuth2ErrorDomain;
extern NSString * const kAFOAuthCodeGrantType;
extern NSString * const kAFOAuthClientCredentialsGrantType;
extern NSString * const kAFOAuthPasswordCredentialsGrantType;
extern NSString * const kAFOAuthRefreshGrantType;
@compatibility_alias AFOAuth2Client AFOAuth2Manager;
@compatibility_alias AFOAuth2RequestOperationManager AFOAuth2Manager;
NS_ASSUME_NONNULL_END
@@ -0,0 +1,298 @@
// AFOAuth2Manager.m
//
// Copyright (c) 2012-2014 AFNetworking (http://afnetworking.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 "AFOAuth2Manager.h"
#import "AFOAuthCredential.h"
NSString * const kAFOAuthClientCredentialsGrantType = @"client_credentials";
NSString * const kAFOAuthPasswordCredentialsGrantType = @"password";
NSString * const kAFOAuthCodeGrantType = @"authorization_code";
NSString * const kAFOAuthRefreshGrantType = @"refresh_token";
NSString * const kAFOAuthFacebookCredentialGrantType = @"provider_facebook_token";
NSString * const AFOAuth2ErrorDomain = @"com.alamofire.networking.oauth2.error";
// See: http://tools.ietf.org/html/rfc6749#section-5.2
static NSError * AFErrorFromRFC6749Section5_2Error(id object) {
if (![object valueForKey:@"error"] || [[object valueForKey:@"error"] isEqual:[NSNull null]]) {
return nil;
}
NSMutableDictionary *mutableUserInfo = [NSMutableDictionary dictionary];
NSString *description = nil;
if ([object valueForKey:@"error_description"]) {
description = [object valueForKey:@"error_description"];
} else {
if ([[object valueForKey:@"error"] isEqualToString:@"invalid_request"]) {
description = NSLocalizedStringFromTable(@"The request is missing a required parameter, includes an unsupported parameter value (other than grant type), repeats a parameter, includes multiple credentials, utilizes more than one mechanism for authenticating the client, or is otherwise malformed.", @"AFOAuth2Manager", @"invalid_request");
} else if ([[object valueForKey:@"error"] isEqualToString:@"invalid_client"]) {
description = NSLocalizedStringFromTable(@"Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method). The authorization server MAY return an HTTP 401 (Unauthorized) status code to indicate which HTTP authentication schemes are supported. If the client attempted to authenticate via the \"Authorization\" request header field, the authorization server MUST respond with an HTTP 401 (Unauthorized) status code and include the \"WWW-Authenticate\" response header field matching the authentication scheme used by the client.", @"AFOAuth2Manager", @"invalid_request");
} else if ([[object valueForKey:@"error"] isEqualToString:@"invalid_grant"]) {
description = NSLocalizedStringFromTable(@"The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.", @"AFOAuth2Manager", @"invalid_request");
} else if ([[object valueForKey:@"error"] isEqualToString:@"unauthorized_client"]) {
description = NSLocalizedStringFromTable(@"The authenticated client is not authorized to use this authorization grant type.", @"AFOAuth2Manager", @"invalid_request");
} else if ([[object valueForKey:@"error"] isEqualToString:@"unsupported_grant_type"]) {
description = NSLocalizedStringFromTable(@"The authorization grant type is not supported by the authorization server.", @"AFOAuth2Manager", @"invalid_request");
}
}
if (description) {
mutableUserInfo[NSLocalizedDescriptionKey] = description;
}
if ([object valueForKey:@"error_uri"]) {
mutableUserInfo[NSLocalizedRecoverySuggestionErrorKey] = [object valueForKey:@"error_uri"];
}
return [NSError errorWithDomain:AFOAuth2ErrorDomain code:-1 userInfo:mutableUserInfo];
}
@interface AFOAuth2Manager()
@property (readwrite, nonatomic, copy) NSString *serviceProviderIdentifier;
@property (readwrite, nonatomic, copy) NSString *clientID;
@property (readwrite, nonatomic, copy) NSString *secret;
@end
@implementation AFOAuth2Manager
+ (instancetype) managerWithBaseURL:(NSURL *)url
clientID:(NSString *)clientID
secret:(NSString *)secret {
return [self managerWithBaseURL:url sessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] clientID:clientID secret:secret];
}
+ (instancetype) managerWithBaseURL:(NSURL *)url
sessionConfiguration:(NSURLSessionConfiguration *)configuration
clientID:(NSString *)clientID
secret:(NSString *)secret {
return [[self alloc] initWithBaseURL:url sessionConfiguration:configuration clientID:clientID secret:secret];
}
- (id)initWithBaseURL:(NSURL *)url
clientID:(NSString *)clientID
secret:(NSString *)secret {
return [self initWithBaseURL:url sessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] clientID:clientID secret:secret];
}
- (id)initWithBaseURL:(NSURL *)url
sessionConfiguration:(NSURLSessionConfiguration *)configuration
clientID:(NSString *)clientID
secret:(NSString *)secret {
NSParameterAssert(url);
NSParameterAssert(clientID);
NSParameterAssert(secret);
self = [super initWithBaseURL:url sessionConfiguration:configuration];
if (!self) {
return nil;
}
self.serviceProviderIdentifier = [self.baseURL host];
self.clientID = clientID;
self.secret = secret;
self.useHTTPBasicAuthentication = YES;
[self.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
return self;
}
#pragma mark -
- (void)setUseHTTPBasicAuthentication:(BOOL)useHTTPBasicAuthentication {
_useHTTPBasicAuthentication = useHTTPBasicAuthentication;
if (self.useHTTPBasicAuthentication) {
[self.requestSerializer setAuthorizationHeaderFieldWithUsername:self.clientID password:self.secret];
} else {
[self.requestSerializer setValue:nil forHTTPHeaderField:@"Authorization"];
}
}
- (void)setSecret:(NSString *)secret {
if (!secret) {
secret = @"";
}
_secret = secret;
}
#pragma mark -
- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString
username:(NSString *)username
password:(NSString *)password
scope:(NSString *)scope
success:(void (^)(AFOAuthCredential * _Nonnull))success
failure:(void (^)(NSError * _Nonnull))failure {
NSParameterAssert(username);
NSParameterAssert(password);
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
[parameters setValue:kAFOAuthPasswordCredentialsGrantType forKey:@"grant_type"];
[parameters setValue:username forKey:@"username"];
[parameters setValue:password forKey:@"password"];
if (scope) {
[parameters setValue:scope forKey:@"scope"];
}
return [self authenticateUsingOAuthWithURLString:URLString parameters:parameters success:success failure:failure];
}
- (NSURLSessionTask *)authenticateUsingFacebookOAuthWithURLString:(NSString *)URLString
facebookID:(NSString *)facebookid
facebookToken:(NSString *)facebookToken
scope:(NSString *)scope
success:(void (^)(AFOAuthCredential * _Nonnull))success
failure:(void (^)(NSError * _Nonnull))failure {
NSParameterAssert(facebookid);
NSParameterAssert(facebookToken);
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
[parameters setValue:kAFOAuthFacebookCredentialGrantType forKey:@"grant_type"];
[parameters setValue:facebookid forKey:@"username"];
[parameters setValue:facebookToken forKey:@"password"];
if (scope) {
[parameters setValue:scope forKey:@"scope"];
}
return [self authenticateUsingOAuthWithURLString:URLString parameters:parameters success:success failure:failure];
}
- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString
scope:(NSString *)scope
success:(void (^)(AFOAuthCredential * _Nonnull))success
failure:(void (^)(NSError * _Nonnull))failure {
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
[parameters setValue:kAFOAuthClientCredentialsGrantType forKey:@"grant_type"];
if (scope) {
[parameters setValue:scope forKey:@"scope"];
}
return [self authenticateUsingOAuthWithURLString:URLString parameters:parameters success:success failure:failure];
}
- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString
refreshToken:(NSString *)refreshToken
success:(void (^)(AFOAuthCredential *credential))success
failure:(void (^)(NSError *error))failure
{
NSParameterAssert(refreshToken);
NSDictionary *parameters = @{
@"grant_type": kAFOAuthRefreshGrantType,
@"refresh_token": refreshToken
};
return [self authenticateUsingOAuthWithURLString:URLString parameters:parameters success:success failure:failure];
}
- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString
code:(NSString *)code
redirectURI:(NSString *)uri
success:(void (^)(AFOAuthCredential *credential))success
failure:(void (^)(NSError *error))failure
{
NSParameterAssert(code);
NSParameterAssert(uri);
NSDictionary *parameters = @{
@"grant_type": kAFOAuthCodeGrantType,
@"code": code,
@"redirect_uri": uri
};
return [self authenticateUsingOAuthWithURLString:URLString parameters:parameters success:success failure:failure];
}
- (NSURLSessionTask *)authenticateUsingOAuthWithURLString:(NSString *)URLString
parameters:(NSDictionary *)parameters
success:(void (^)(AFOAuthCredential *credential))success
failure:(void (^)(NSError *error))failure
{
NSMutableDictionary *mutableParameters = [NSMutableDictionary dictionaryWithDictionary:parameters];
if (!self.useHTTPBasicAuthentication) {
mutableParameters[@"client_id"] = self.clientID;
mutableParameters[@"client_secret"] = self.secret;
}
parameters = [NSDictionary dictionaryWithDictionary:mutableParameters];
NSURLSessionTask *task;
task = [self POST:URLString parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
if (!responseObject) {
if (failure) {
failure(nil);
}
return;
}
if ([responseObject valueForKey:@"error"]) {
if (failure) {
failure(AFErrorFromRFC6749Section5_2Error(responseObject));
}
}
NSString *refreshToken = [responseObject valueForKey:@"refresh_token"];
if (!refreshToken || [refreshToken isEqual:[NSNull null]]) {
refreshToken = [parameters valueForKey:@"refresh_token"];
}
AFOAuthCredential *credential = [AFOAuthCredential credentialWithOAuthToken:[responseObject valueForKey:@"access_token"] tokenType:[responseObject valueForKey:@"token_type"]];
if (refreshToken) { // refreshToken is optional in the OAuth2 spec
[credential setRefreshToken:refreshToken];
}
// Expiration is optional, but recommended in the OAuth2 spec. It not provide, assume distantFuture === never expires
NSDate *expireDate = [NSDate distantFuture];
id expiresIn = [responseObject valueForKey:@"expires_in"];
if (expiresIn && ![expiresIn isEqual:[NSNull null]]) {
expireDate = [NSDate dateWithTimeIntervalSinceNow:[expiresIn doubleValue]];
}
if (expireDate) {
[credential setExpiration:expireDate];
}
if (success) {
success(credential);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if (failure) {
failure(error);
}
}];
return task;
}
@end
@@ -0,0 +1,158 @@
// AFOAuthCredential.h
//
// Copyright (c) 2012-2014 AFNetworking (http://afnetworking.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 <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
`AFOAuthCredential` models the credentials returned from an OAuth server, storing the token type, access & refresh tokens, and whether the token is expired.
OAuth credentials can be stored in the user's keychain, and retrieved on subsequent launches.
*/
@interface AFOAuthCredential : NSObject <NSCoding>
///--------------------------------------
/// @name Accessing Credential Properties
///--------------------------------------
/**
The OAuth access token.
*/
@property (readonly, nonatomic, copy) NSString *accessToken;
/**
The OAuth token type (e.g. "bearer").
*/
@property (readonly, nonatomic, copy) NSString *tokenType;
/**
The OAuth refresh token.
*/
@property (readonly, nonatomic, copy) NSString *refreshToken;
/**
Whether the OAuth credentials are expired.
*/
@property (readonly, nonatomic, assign, getter = isExpired) BOOL expired;
///--------------------------------------------
/// @name Creating and Initializing Credentials
///--------------------------------------------
/**
Create an OAuth credential from a token string, with a specified type.
@param token The OAuth token string.
@param type The OAuth token type.
*/
+ (instancetype)credentialWithOAuthToken:(NSString *)token
tokenType:(NSString *)type;
/**
Initialize an OAuth credential from a token string, with a specified type.
@param token The OAuth token string.
@param type The OAuth token type.
*/
- (id)initWithOAuthToken:(NSString *)token
tokenType:(NSString *)type;
///----------------------------
/// @name Setting Refresh Token
///----------------------------
/**
Set the credential refresh token, without a specific expiration
@param refreshToken The OAuth refresh token.
*/
- (void)setRefreshToken:(NSString *)refreshToken;
/**
Set the expiration on the access token. If no expiration is given by the OAuth2 provider,
you may pass in [NSDate distantFuture]
@param expiration The expiration of the access token. This must not be `nil`.
*/
- (void)setExpiration:(NSDate *)expiration;
/**
Set the credential refresh token, with a specified expiration.
@param refreshToken The OAuth refresh token.
@param expiration The expiration of the access token. This must not be `nil`.
*/
- (void)setRefreshToken:(NSString *)refreshToken
expiration:(NSDate *)expiration;
///-----------------------------------------
/// @name Storing and Retrieving Credentials
///-----------------------------------------
/**
Stores the specified OAuth credential for a given web service identifier in the Keychain.
with the default Keychain Accessibilty of kSecAttrAccessibleWhenUnlocked.
@param credential The OAuth credential to be stored.
@param identifier The service identifier associated with the specified credential.
@return Whether or not the credential was stored in the keychain.
*/
+ (BOOL)storeCredential:(AFOAuthCredential *)credential
withIdentifier:(NSString *)identifier;
/**
Stores the specified OAuth token for a given web service identifier in the Keychain.
@param credential The OAuth credential to be stored.
@param identifier The service identifier associated with the specified token.
@param securityAccessibility The Keychain security accessibility to store the credential with.
@return Whether or not the credential was stored in the keychain.
*/
+ (BOOL)storeCredential:(AFOAuthCredential *)credential
withIdentifier:(NSString *)identifier
withAccessibility:(id)securityAccessibility;
/**
Retrieves the OAuth credential stored with the specified service identifier from the Keychain.
@param identifier The service identifier associated with the specified credential.
@return The retrieved OAuth credential.
*/
+ (nullable AFOAuthCredential *)retrieveCredentialWithIdentifier:(NSString *)identifier;
/**
Deletes the OAuth credential stored with the specified service identifier from the Keychain.
@param identifier The service identifier associated with the specified credential.
@return Whether or not the credential was deleted from the keychain.
*/
+ (BOOL)deleteCredentialWithIdentifier:(NSString *)identifier;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,184 @@
// AFOAuthCredential.m
//
// Copyright (c) 2012-2014 AFNetworking (http://afnetworking.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 "AFOAuthCredential.h"
NSString * const kAFOAuth2CredentialServiceName = @"AFOAuthCredentialService";
static NSDictionary * AFKeychainQueryDictionaryWithIdentifier(NSString *identifier) {
NSCParameterAssert(identifier);
return @{
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService: kAFOAuth2CredentialServiceName,
(__bridge id)kSecAttrAccount: identifier
};
}
@interface AFOAuthCredential()
@property (readwrite, nonatomic, copy) NSString *accessToken;
@property (readwrite, nonatomic, copy) NSString *tokenType;
@property (readwrite, nonatomic, copy) NSString *refreshToken;
@property (readwrite, nonatomic, copy) NSDate *expiration;
@end
@implementation AFOAuthCredential
//@dynamic expired;
#pragma mark -
+ (instancetype)credentialWithOAuthToken:(NSString *)token
tokenType:(NSString *)type
{
return [[self alloc] initWithOAuthToken:token tokenType:type];
}
- (id)initWithOAuthToken:(NSString *)token
tokenType:(NSString *)type
{
self = [super init];
if (!self) {
return nil;
}
self.accessToken = token;
self.tokenType = type;
return self;
}
- (NSString *)description {
return [NSString stringWithFormat:@"<%@ accessToken:\"%@\" tokenType:\"%@\" refreshToken:\"%@\" expiration:\"%@\">", [self class], self.accessToken, self.tokenType, self.refreshToken, self.expiration];
}
- (void)setRefreshToken:(NSString *)refreshToken
{
_refreshToken = refreshToken;
}
- (void)setExpiration:(NSDate *)expiration
{
_expiration = expiration;
}
- (void)setRefreshToken:(NSString *)refreshToken
expiration:(NSDate *)expiration
{
NSParameterAssert(refreshToken);
NSParameterAssert(expiration);
self.refreshToken = refreshToken;
self.expiration = expiration;
}
- (BOOL)isExpired {
return [self.expiration compare:[NSDate date]] == NSOrderedAscending;
}
#pragma mark Keychain
+ (BOOL)storeCredential:(AFOAuthCredential *)credential
withIdentifier:(NSString *)identifier
{
id securityAccessibility = nil;
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 43000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wtautological-compare"
if (&kSecAttrAccessibleWhenUnlocked != NULL) {
securityAccessibility = (__bridge id)kSecAttrAccessibleWhenUnlocked;
}
#pragma clang diagnostic pop
#endif
return [[self class] storeCredential:credential withIdentifier:identifier withAccessibility:securityAccessibility];
}
+ (BOOL)storeCredential:(AFOAuthCredential *)credential
withIdentifier:(NSString *)identifier
withAccessibility:(id)securityAccessibility
{
NSMutableDictionary *queryDictionary = [AFKeychainQueryDictionaryWithIdentifier(identifier) mutableCopy];
NSMutableDictionary *updateDictionary = [NSMutableDictionary dictionary];
updateDictionary[(__bridge id)kSecValueData] = [NSKeyedArchiver archivedDataWithRootObject:credential];
if (securityAccessibility) {
updateDictionary[(__bridge id)kSecAttrAccessible] = securityAccessibility;
}
OSStatus status;
BOOL exists = ([self retrieveCredentialWithIdentifier:identifier] != nil);
if (exists) {
status = SecItemUpdate((__bridge CFDictionaryRef)queryDictionary, (__bridge CFDictionaryRef)updateDictionary);
} else {
[queryDictionary addEntriesFromDictionary:updateDictionary];
status = SecItemAdd((__bridge CFDictionaryRef)queryDictionary, NULL);
}
return (status == errSecSuccess);
}
+ (BOOL)deleteCredentialWithIdentifier:(NSString *)identifier {
NSMutableDictionary *queryDictionary = [AFKeychainQueryDictionaryWithIdentifier(identifier) mutableCopy];
OSStatus status = SecItemDelete((__bridge CFDictionaryRef)queryDictionary);
return (status == errSecSuccess);
}
+ (AFOAuthCredential *)retrieveCredentialWithIdentifier:(NSString *)identifier {
NSMutableDictionary *queryDictionary = [AFKeychainQueryDictionaryWithIdentifier(identifier) mutableCopy];
queryDictionary[(__bridge id)kSecReturnData] = (__bridge id)kCFBooleanTrue;
queryDictionary[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
CFDataRef result = nil;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)queryDictionary, (CFTypeRef *)&result);
if (status != errSecSuccess) {
return nil;
}
return [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge_transfer NSData *)result];
}
#pragma mark - NSCoding
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
self.accessToken = [decoder decodeObjectForKey:NSStringFromSelector(@selector(accessToken))];
self.tokenType = [decoder decodeObjectForKey:NSStringFromSelector(@selector(tokenType))];
self.refreshToken = [decoder decodeObjectForKey:NSStringFromSelector(@selector(refreshToken))];
self.expiration = [decoder decodeObjectForKey:NSStringFromSelector(@selector(expiration))];
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.accessToken forKey:NSStringFromSelector(@selector(accessToken))];
[encoder encodeObject:self.tokenType forKey:NSStringFromSelector(@selector(tokenType))];
[encoder encodeObject:self.refreshToken forKey:NSStringFromSelector(@selector(refreshToken))];
[encoder encodeObject:self.expiration forKey:NSStringFromSelector(@selector(expiration))];
}
@end