├── BaasBox-iOS-SDK ├── BAAClient.h ├── BAAClient.m ├── BAAFile.h ├── BAAFile.m ├── BAAGlobals.h ├── BAAGlobals.m ├── BAAMutableURLRequest.h ├── BAAMutableURLRequest.m ├── BAAObject.h ├── BAAObject.m ├── BAAUser.h ├── BAAUser.m ├── BaasBox.h └── BaasBox.m ├── BaasBoxSDK.podspec ├── LICENSE └── README.md /BaasBox-iOS-SDK/BAAClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014. BaasBox 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and limitations under the License. 14 | */ 15 | 16 | #import "BAAObject.h" 17 | #import "BAAGlobals.h" 18 | #import "BaasBox.h" 19 | #import "BAAFile.h" 20 | #import "BAAUser.h" 21 | 22 | @class BAAFile; 23 | @class BAAUser; 24 | 25 | @interface BAAClient : NSObject 26 | 27 | @property (nonatomic, strong) BAAUser *currentUser; 28 | @property (nonatomic, strong, readonly) NSURL *baseURL; 29 | 30 | + (instancetype)sharedClient; 31 | 32 | // Authentication 33 | - (void)authenticateUser:(NSString *)username 34 | password:(NSString *)password 35 | completion:(BAABooleanResultBlock)completionBlock; 36 | 37 | - (void)createUserWithUsername:(NSString *)username 38 | password:(NSString *)password 39 | completion:(BAABooleanResultBlock)completionBlock; 40 | 41 | - (void)createUserWithUsername:(NSString *)username 42 | password:(NSString *)password 43 | visibleByTheUser:(NSDictionary *)visibleByTheUser 44 | visibleByFriends:(NSDictionary *)visibleByFriends 45 | visibleByRegisteredUsers:(NSDictionary *)visibleByRegisteredUsers 46 | visibleByAnonymousUsers:(NSDictionary *)visibleByAnonymousUsers 47 | completion:(BAABooleanResultBlock)completionBlock; 48 | 49 | - (BOOL) isAuthenticated; 50 | 51 | - (void) logoutWithCompletion:(BAABooleanResultBlock)completionBlock; 52 | 53 | // Loading 54 | - (void) loadObject:(BAAObject *)object completion:(BAAObjectResultBlock)completionBlock; 55 | - (void) loadCollection:(BAAObject *)object completion:(BAAArrayResultBlock)completionBlock; 56 | - (void) loadCollection:(BAAObject *)object withParams:(NSDictionary *)parameters completion:(BAAArrayResultBlock)completionBlock; 57 | 58 | // saving 59 | - (void) createObject:(BAAObject *)object completion:(BAAObjectResultBlock)completionBlock; 60 | - (void) updateObject:(BAAObject *)object completion:(BAAObjectResultBlock)completionBlock; 61 | 62 | // Deleting 63 | - (void) deleteObject:(BAAObject *)object completion:(BAABooleanResultBlock)completionBlock; 64 | 65 | // Counting 66 | - (void) fetchCountForObjects:(BAAObject *)object completion:(BAAIntegerResultBlock)completionBlock; 67 | 68 | // Push notifications 69 | - (void) askToEnablePushNotifications; 70 | - (void) enablePushNotifications:(NSData *)token completion:(BAABooleanResultBlock)completionBlock; 71 | - (void) disablePushNotificationsWithCompletion:(BAABooleanResultBlock)completionBlock; 72 | - (void) pushNotificationToUsername:(NSString *)username withMessage:(NSString *)message completion:(BAABooleanResultBlock)completionBlock; 73 | - (void) pushNotificationToUsername:(NSString *)username withMessage:(NSString *)message customPayload:(NSDictionary *)customPayload completion:(BAABooleanResultBlock)completionBlock; 74 | 75 | // Files 76 | - (void) loadFiles:(BAAFile *)file completion:(BAAArrayResultBlock)completionBlock; 77 | - (void) loadFiles:(BAAFile *)file withParams:(NSDictionary *) parameters completion:(BAAArrayResultBlock)completionBlock; 78 | - (NSURLSessionDataTask *) loadFileData:(BAAFile *)file completion:(void(^)(NSData *data, NSError *error))completionBlock; 79 | - (NSURLSessionDataTask *) loadFileData:(BAAFile *)file parameters:(NSDictionary *)parameters completion:(void(^)(NSData *data, NSError *error))completionBlock; 80 | - (void) uploadFile:(BAAFile *)file withPermissions:(NSDictionary *)permissions completion:(BAAObjectResultBlock)completionBlock; 81 | - (void) deleteFile:(BAAFile *)file completion:(BAABooleanResultBlock)completionBlock; 82 | - (void) loadFileDetails:(NSString *)fileID completion:(BAAObjectResultBlock)completionBlock; 83 | - (void) loadFilesAndDetailsWithCompletion:(BAAArrayResultBlock)completionBlock; 84 | 85 | // User 86 | - (void) loadCurrentUserWithCompletion:(BAAObjectResultBlock)completionBlock; 87 | - (void) updateUserWithCompletion:(BAAObjectResultBlock)completionBlock; 88 | - (void) loadUsersWithCompletion:(BAAArrayResultBlock)completionBlock; 89 | - (void) loadUsersWithParameters:(NSDictionary *)parameters completion:(BAAArrayResultBlock)completionBlock; 90 | - (void) loadUsersDetails:(NSString *) userId completion:(BAAObjectResultBlock)completionBlock; 91 | - (void) loadFollowingForUser:(BAAUser *)user completion:(BAAArrayResultBlock)completionBlock; 92 | - (void) loadFollowersOfUser:(BAAUser *)user completion:(BAAArrayResultBlock)completionBlock; 93 | - (void) followUser:(BAAUser *)user completion:(BAAObjectResultBlock)completionBlock; 94 | - (void) unfollowUser:(BAAUser *)user completion:(BAABooleanResultBlock)completionBlock; 95 | 96 | // Acl 97 | - (void) grantAccess:(id)element toRole:(NSString *)roleName accessType:(NSString *)access completion:(BAAObjectResultBlock)completionBlock; 98 | - (void) grantAccess:(id)element toUser:(NSString *)username accessType:(NSString *)access completion:(BAAObjectResultBlock)completionBlock; 99 | - (void) revokeAccess:(id)element toRole:(NSString *)roleName accessType:(NSString *)access completion:(BAAObjectResultBlock)completionBlock; 100 | - (void) revokeAccess:(id)element toUser:(NSString *)username accessType:(NSString *)access completion:(BAAObjectResultBlock)completionBlock; 101 | 102 | // Password 103 | - (void) changeOldPassword:(NSString *)oldPassword toNewPassword:(NSString *)newPassword completion:(BAABooleanResultBlock)completionBlock; 104 | - (void) resetPasswordForUsername:(NSString *)username withCompletion:(BAABooleanResultBlock)completionBlock; 105 | 106 | // Admin 107 | - (void) createCollection:(NSString *)collectionName completion:(BAAObjectResultBlock)completionBlock; 108 | - (void) loadSettingsWithCompletion:(BAAObjectResultBlock)completionBlock; 109 | - (void) loadSettingsSection:(NSString *)sectionName completion:(BAAObjectResultBlock)completionBlock; 110 | - (void) setValue:(NSString *)value forKey:(NSString *)key inSection:(NSString *)sectionName completion:(BAAObjectResultBlock)completionBlock; 111 | 112 | 113 | // Core methods 114 | - (void)getPath:(NSString *)path 115 | parameters:(NSDictionary *)parameters 116 | success:(void (^)(id responseObject))success 117 | failure:(void (^)(NSError *error))failure; 118 | 119 | - (void)postPath:(NSString *)path 120 | parameters:(NSDictionary *)parameters 121 | success:(void (^)(id responseObject))success 122 | failure:(void (^)(NSError *error))failure; 123 | 124 | - (void)putPath:(NSString *)path 125 | parameters:(NSDictionary *)parameters 126 | success:(void (^)(id responseObject))success 127 | failure:(void (^)(NSError *error))failure; 128 | 129 | - (void)deletePath:(NSString *)path 130 | parameters:(NSDictionary *)parameters 131 | success:(void (^)(id responseObject))success 132 | failure:(void (^)(NSError *error))failure; 133 | 134 | - (void) saveUserToDisk:(BAAUser *)user; 135 | 136 | // Pagination constants 137 | extern NSString * const kPageNumberKey; 138 | extern NSString * const kPageSizeKey; 139 | extern NSInteger const kPageLength; 140 | 141 | // Role constants 142 | extern NSString * const kAclAnonymousRole; 143 | extern NSString * const kAclRegisteredRole; 144 | extern NSString * const kAclAdministratorRole; 145 | 146 | // ACL constants 147 | extern NSString * const kAclReadPermission; 148 | extern NSString * const kAclDeletePermission; 149 | extern NSString * const kAclUpdatePermission; 150 | extern NSString * const kAclAllPermission; 151 | 152 | // Push Notification constants 153 | extern NSString * const kPushNotificationMessageKey; 154 | extern NSString * const kPushNotificationCustomPayloadKey; 155 | 156 | // Authentication expired notification 157 | extern NSString * const kAuthenticationTokenExpiredNotification; 158 | 159 | @end -------------------------------------------------------------------------------- /BaasBox-iOS-SDK/BAAClient.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014. BaasBox 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and limitations under the License. 14 | */ 15 | 16 | #import "BAAClient.h" 17 | #import "BaasBox.h" 18 | #import "BAAMutableURLRequest.h" 19 | 20 | NSString * const kPageNumberKey = @"page"; 21 | NSString * const kPageSizeKey = @"recordsPerPage"; 22 | NSString * const kSkipKey = @"skip"; 23 | NSInteger const kPageLength = 50; 24 | 25 | NSString * const kAclAnonymousRole = @"anonymous"; 26 | NSString * const kAclRegisteredRole = @"registered"; 27 | NSString * const kAclAdministratorRole = @"administrator"; 28 | 29 | NSString * const kAclReadPermission = @"read"; 30 | NSString * const kAclDeletePermission = @"delete"; 31 | NSString * const kAclUpdatePermission = @"update"; 32 | NSString * const kAclAllPermission = @"all"; 33 | 34 | NSString * const kPushNotificationMessageKey = @"message"; 35 | NSString * const kPushNotificationCustomPayloadKey = @"custom"; 36 | NSString * const kAuthenticationTokenExpiredNotification = @"com.baasbox.tokenExpired"; 37 | 38 | static NSString * const boundary = @"BAASBOX_BOUNDARY_STRING"; 39 | 40 | static NSString * const kBAACharactersToBeEscapedInQuery = @"@/:?&=$;+!#()',*"; 41 | 42 | static NSString * BAAPercentEscapedQueryStringKeyFromStringWithEncoding(NSString *string, NSStringEncoding encoding) { 43 | static NSString * const kBAACharactersToLeaveUnescapedInQueryStringPairKey = @"[]."; 44 | 45 | return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, (__bridge CFStringRef)kBAACharactersToLeaveUnescapedInQueryStringPairKey, (__bridge CFStringRef)kBAACharactersToBeEscapedInQuery, CFStringConvertNSStringEncodingToEncoding(encoding)); 46 | } 47 | 48 | static NSString * BAAPercentEscapedQueryStringValueFromStringWithEncoding(NSString *string, NSStringEncoding encoding) { 49 | return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)string, NULL, (__bridge CFStringRef)kBAACharactersToBeEscapedInQuery, CFStringConvertNSStringEncodingToEncoding(encoding)); 50 | } 51 | 52 | #pragma mark - URL Serialization borrowed from AFNetworking 53 | 54 | @interface BAAQueryStringPair : NSObject 55 | @property (readwrite, nonatomic, strong) id field; 56 | @property (readwrite, nonatomic, strong) id value; 57 | 58 | - (id)initWithField:(id)field value:(id)value; 59 | 60 | - (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding; 61 | @end 62 | 63 | @implementation BAAQueryStringPair 64 | 65 | - (id)initWithField:(id)field value:(id)value { 66 | self = [super init]; 67 | if (!self) { 68 | return nil; 69 | } 70 | 71 | self.field = field; 72 | self.value = value; 73 | 74 | return self; 75 | } 76 | 77 | - (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding { 78 | if (!self.value || [self.value isEqual:[NSNull null]]) { 79 | return BAAPercentEscapedQueryStringKeyFromStringWithEncoding([self.field description], stringEncoding); 80 | } else { 81 | return [NSString stringWithFormat:@"%@=%@", BAAPercentEscapedQueryStringKeyFromStringWithEncoding([self.field description], stringEncoding), BAAPercentEscapedQueryStringValueFromStringWithEncoding([self.value description], stringEncoding)]; 82 | } 83 | } 84 | 85 | @end 86 | 87 | 88 | extern NSArray * BAAQueryStringPairsFromDictionary(NSDictionary *dictionary); 89 | extern NSArray * BAAQueryStringPairsFromKeyAndValue(NSString *key, id value); 90 | 91 | static NSString * BAAQueryStringFromParametersWithEncoding(NSDictionary *parameters, NSStringEncoding stringEncoding) { 92 | NSMutableArray *mutablePairs = [NSMutableArray array]; 93 | for (BAAQueryStringPair *pair in BAAQueryStringPairsFromDictionary(parameters)) { 94 | [mutablePairs addObject:[pair URLEncodedStringValueWithEncoding:stringEncoding]]; 95 | } 96 | 97 | return [mutablePairs componentsJoinedByString:@"&"]; 98 | } 99 | 100 | NSArray * BAAQueryStringPairsFromDictionary(NSDictionary *dictionary) { 101 | return BAAQueryStringPairsFromKeyAndValue(nil, dictionary); 102 | } 103 | 104 | NSArray * BAAQueryStringPairsFromKeyAndValue(NSString *key, id value) { 105 | NSMutableArray *mutableQueryStringComponents = [NSMutableArray array]; 106 | 107 | if ([value isKindOfClass:[NSDictionary class]]) { 108 | NSDictionary *dictionary = value; 109 | 110 | NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(caseInsensitiveCompare:)]; 111 | for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) { 112 | id nestedValue = [dictionary objectForKey:nestedKey]; 113 | if (nestedValue) { 114 | [mutableQueryStringComponents addObjectsFromArray:BAAQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)]; 115 | } 116 | } 117 | } else if ([value isKindOfClass:[NSArray class]]) { 118 | NSArray *array = value; 119 | for (id nestedValue in array) { 120 | [mutableQueryStringComponents addObjectsFromArray:BAAQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)]; 121 | } 122 | } else if ([value isKindOfClass:[NSSet class]]) { 123 | NSSet *set = value; 124 | for (id obj in set) { 125 | [mutableQueryStringComponents addObjectsFromArray:BAAQueryStringPairsFromKeyAndValue(key, obj)]; 126 | } 127 | } else { 128 | [mutableQueryStringComponents addObject:[[BAAQueryStringPair alloc] initWithField:key value:value]]; 129 | } 130 | 131 | return mutableQueryStringComponents; 132 | } 133 | 134 | 135 | #pragma mark - Client 136 | 137 | @interface BAAClient () 138 | 139 | @property (nonatomic, copy) NSString *appCode; 140 | @property (nonatomic, strong) NSURLSession *session; 141 | 142 | - (BAAUser *) loadUserFromDisk; 143 | - (void)_initSession; 144 | 145 | @end 146 | 147 | NSString* const BAAUserKeyForUserDefaults = @"com.baaxbox.user"; 148 | 149 | @implementation BAAClient 150 | 151 | + (instancetype)sharedClient { 152 | 153 | static BAAClient *sharedBAAClient = nil; 154 | static dispatch_once_t onceBAAToken; 155 | dispatch_once(&onceBAAToken, ^{ 156 | sharedBAAClient = [[BAAClient alloc] init]; 157 | }); 158 | 159 | return sharedBAAClient; 160 | } 161 | 162 | - (id) init { 163 | 164 | if (self = [super init]) { 165 | 166 | _baseURL = [NSURL URLWithString:[BaasBox baseURL]]; 167 | _appCode = [BaasBox appCode]; 168 | [self _initSession]; 169 | 170 | } 171 | 172 | return self; 173 | } 174 | 175 | - (void) _initSession { 176 | 177 | self.currentUser = [self loadUserFromDisk]; 178 | NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; 179 | NSDictionary *headers = @{@"Accept": @"application/json", 180 | @"User-Agent": [NSString stringWithFormat:@"BaasBox iOS SDK %@", VERSION]}; 181 | sessionConfiguration.HTTPAdditionalHeaders = headers; 182 | _session = [NSURLSession sessionWithConfiguration:sessionConfiguration 183 | delegate:nil 184 | delegateQueue:[NSOperationQueue mainQueue]]; 185 | 186 | } 187 | 188 | #pragma mark - Authentication 189 | 190 | - (void)authenticateUser:(NSString *)username 191 | password:(NSString *)password 192 | completion:(BAABooleanResultBlock)completionHandler { 193 | 194 | [self postPath:@"login" 195 | parameters:@{@"username" : username, @"password": password, @"appcode" : self.appCode} 196 | success:^(NSDictionary *responseObject) { 197 | 198 | NSString *token = responseObject[@"data"][@"X-BB-SESSION"]; 199 | 200 | if (token) { 201 | 202 | BAAUser *user = [[BAAUser alloc] initWithDictionary:responseObject[@"data"]]; 203 | user.authenticationToken = token; 204 | self.currentUser = user; 205 | [self saveUserToDisk:user]; 206 | completionHandler(YES, nil); 207 | 208 | } else { 209 | 210 | NSMutableDictionary *errorDetail = [NSMutableDictionary dictionary]; 211 | [errorDetail setValue:responseObject[@"message"] 212 | forKey:NSLocalizedDescriptionKey]; 213 | NSError *error = [NSError errorWithDomain:[BaasBox errorDomain] 214 | code:[BaasBox errorCode] 215 | userInfo:errorDetail]; 216 | completionHandler(NO, error); 217 | 218 | } 219 | 220 | } failure:^(NSError *error) { 221 | 222 | completionHandler(NO, error); 223 | 224 | }]; 225 | 226 | } 227 | 228 | - (void)createUserWithUsername:(NSString *)username 229 | password:(NSString *)password 230 | completion:(BAABooleanResultBlock)completionHandler { 231 | 232 | [self createUserWithUsername:username 233 | password:password 234 | visibleByTheUser:nil 235 | visibleByFriends:nil 236 | visibleByRegisteredUsers:nil 237 | visibleByAnonymousUsers:nil 238 | completion:completionHandler]; 239 | 240 | } 241 | 242 | - (void)createUserWithUsername:(NSString *)username 243 | password:(NSString *)password 244 | visibleByTheUser:(NSDictionary *)visibleByTheUser 245 | visibleByFriends:(NSDictionary *)visibleByFriends 246 | visibleByRegisteredUsers:(NSDictionary *)visibleByRegisteredUsers 247 | visibleByAnonymousUsers:(NSDictionary *)visibleByAnonymousUsers 248 | completion:(BAABooleanResultBlock)completionHandler { 249 | 250 | [self postPath:@"user" 251 | parameters:@{ 252 | @"username" : username, 253 | @"password": password, 254 | @"appcode" : self.appCode, 255 | @"visibleByTheUser" : visibleByTheUser ?: @{}, 256 | @"visibleByFriends" : visibleByFriends ?: @{}, 257 | @"visibleByRegisteredUsers" : visibleByRegisteredUsers ?: @{}, 258 | @"visibleByAnonymousUsers" : visibleByAnonymousUsers ?: @{}} 259 | success:^(NSDictionary *responseObject) { 260 | 261 | NSString *token = responseObject[@"data"][@"X-BB-SESSION"]; 262 | 263 | if (token) { 264 | 265 | BAAUser *user = [[BAAUser alloc] initWithDictionary:responseObject[@"data"]]; 266 | user.authenticationToken = token; 267 | self.currentUser = user; 268 | [self saveUserToDisk:user]; 269 | 270 | completionHandler(YES, nil); 271 | 272 | } else { 273 | 274 | NSMutableDictionary *errorDetail = [NSMutableDictionary dictionary]; 275 | [errorDetail setValue:responseObject[@"message"] 276 | forKey:NSLocalizedDescriptionKey]; 277 | NSError *error = [NSError errorWithDomain:[BaasBox errorDomain] 278 | code:[BaasBox errorCode] 279 | userInfo:errorDetail]; 280 | completionHandler(NO, error); 281 | 282 | } 283 | 284 | } failure:^(NSError *error) { 285 | 286 | completionHandler(NO, error); 287 | 288 | }]; 289 | 290 | } 291 | 292 | - (void) logoutWithCompletion:(BAABooleanResultBlock)completionHandler { 293 | 294 | NSString *path = @"logout"; 295 | 296 | if (self.currentUser.pushNotificationToken) { 297 | path = [NSString stringWithFormat:@"logout/%@", self.currentUser.pushNotificationToken]; 298 | } 299 | 300 | [self postPath:path 301 | parameters:nil 302 | success:^(id responseObject) { 303 | 304 | if (completionHandler) { 305 | self.currentUser = nil; 306 | [self saveUserToDisk:self.currentUser]; 307 | completionHandler(YES, nil); 308 | } 309 | 310 | } failure:^(NSError *error) { 311 | 312 | if (completionHandler) { 313 | completionHandler(NO, error); 314 | } 315 | 316 | }]; 317 | 318 | } 319 | 320 | #pragma mark - Objects 321 | 322 | - (void) loadObject:(BAAObject *)object completion:(BAAObjectResultBlock)completionBlock { 323 | 324 | [self getPath:[NSString stringWithFormat:@"%@/%@", object.collectionName, object.objectId] 325 | parameters:nil 326 | success:^(id responseObject) { 327 | 328 | NSDictionary *d = responseObject[@"data"]; 329 | 330 | if (d) { 331 | 332 | id c = [object class]; 333 | id newObject = [[c alloc] initWithDictionary:d]; 334 | completionBlock(newObject, nil); 335 | 336 | } else { 337 | 338 | NSMutableDictionary *errorDetail = [NSMutableDictionary dictionary]; 339 | [errorDetail setValue:responseObject[@"message"] 340 | forKey:NSLocalizedDescriptionKey]; 341 | NSError *error = [NSError errorWithDomain:[BaasBox errorDomain] 342 | code:[BaasBox errorCode] 343 | userInfo:errorDetail]; 344 | completionBlock(nil, error); 345 | 346 | } 347 | 348 | } failure:^(NSError *error) { 349 | 350 | completionBlock(nil, error); 351 | 352 | }]; 353 | 354 | } 355 | 356 | - (void) loadCollection:(BAAObject *)object withParams:(NSDictionary *)parameters completion:(BAAArrayResultBlock)completionBlock { 357 | 358 | [self getPath:object.collectionName 359 | parameters:parameters 360 | success:^(id responseObject) { 361 | 362 | NSArray *objects = responseObject[@"data"]; 363 | NSMutableArray *result = [NSMutableArray array]; 364 | 365 | for (NSDictionary *d in objects) { 366 | 367 | id c = [object class]; 368 | id newObject = [[c alloc] initWithDictionary:d]; 369 | [result addObject:newObject]; 370 | 371 | } 372 | 373 | completionBlock(result, nil); 374 | 375 | 376 | } failure:^(NSError *error) { 377 | 378 | completionBlock(nil, error); 379 | 380 | }]; 381 | 382 | } 383 | 384 | 385 | - (void) loadCollection:(BAAObject *)object completion:(BAAArrayResultBlock)completionBlock { 386 | 387 | [self loadCollection:object 388 | withParams:@{kPageNumberKey : @0, 389 | kPageSizeKey : [NSNumber numberWithInteger:kPageLength]} 390 | completion:completionBlock]; 391 | 392 | } 393 | 394 | - (void) createObject:(BAAObject *)object completion:(BAAObjectResultBlock)completionBlock { 395 | 396 | [self postPath:object.collectionName 397 | parameters:object.objectAsDictionary 398 | success:^(id responseObject) { 399 | 400 | NSDictionary *d = responseObject[@"data"]; 401 | id c = [object class]; 402 | id newObject = [[c alloc] initWithDictionary:d]; 403 | completionBlock(newObject, nil); 404 | 405 | } failure:^(NSError *error) { 406 | 407 | completionBlock(nil, error); 408 | 409 | }]; 410 | 411 | } 412 | 413 | - (void) updateObject:(BAAObject *)object completion:(BAAObjectResultBlock)completionBlock { 414 | 415 | [self putPath:[NSString stringWithFormat:@"%@/%@", object.collectionName, object.objectId] 416 | parameters:object.objectAsDictionary 417 | success:^(id responseObject) { 418 | 419 | NSDictionary *d = responseObject[@"data"]; 420 | id c = [object class]; 421 | id newObject = [[c alloc] initWithDictionary:d]; 422 | completionBlock(newObject, nil); 423 | 424 | } failure:^(NSError *error) { 425 | 426 | completionBlock(nil, error); 427 | 428 | 429 | }]; 430 | 431 | } 432 | 433 | 434 | - (void) deleteObject:(BAAObject *)object completion:(BAABooleanResultBlock)completionBlock { 435 | 436 | [self deletePath:[NSString stringWithFormat:@"%@/%@", object.collectionName, object.objectId] 437 | parameters:nil 438 | success:^(id responseObject) { 439 | 440 | //BOOL res = operation.response.statusCode == 200; 441 | completionBlock(YES, nil); 442 | 443 | } failure:^(NSError *error) { 444 | 445 | completionBlock(NO, error); 446 | 447 | 448 | }]; 449 | 450 | } 451 | 452 | - (void) fetchCountForObjects:(BAAObject *)object completion:(BAAIntegerResultBlock)completionBlock { 453 | 454 | [self getPath:[NSString stringWithFormat:@"%@/count", object.collectionName] 455 | parameters:nil 456 | success:^(id responseObject) { 457 | 458 | NSInteger result = [responseObject[@"data"][@"count"] intValue]; 459 | 460 | if (completionBlock) { 461 | completionBlock(result, nil); 462 | } 463 | 464 | } failure:^(NSError *error) { 465 | 466 | if (completionBlock) { 467 | completionBlock(-1, error); 468 | } 469 | 470 | }]; 471 | 472 | } 473 | 474 | #pragma Files 475 | 476 | - (void) loadFiles:(BAAFile *)file completion:(BAAArrayResultBlock)completionBlock { 477 | 478 | [self loadFiles:file 479 | withParams:@{@"orderBy" :@"_creation_date%20desc"} 480 | completion:completionBlock]; 481 | 482 | } 483 | 484 | - (void) loadFiles:(BAAFile *)file withParams:(NSDictionary *)parameters completion:(BAAArrayResultBlock)completionBlock { 485 | 486 | [self getPath:@"/file/details" 487 | parameters:parameters 488 | success:^(id responseObject) { 489 | 490 | NSArray *objects = responseObject[@"data"]; 491 | NSMutableArray *result = [NSMutableArray array]; 492 | 493 | for (NSDictionary *d in objects) { 494 | 495 | id c = [file class]; 496 | id newObject = [[c alloc] initWithDictionary:d]; 497 | [result addObject:newObject]; 498 | 499 | } 500 | 501 | completionBlock(result, nil); 502 | 503 | 504 | } failure:^(NSError *error) { 505 | 506 | completionBlock(nil, error); 507 | 508 | }]; 509 | 510 | } 511 | 512 | - (NSURLSessionDataTask *) loadFileData:(BAAFile *)file completion:(void(^)(NSData *data, NSError *error))completionBlock { 513 | 514 | return [self loadFileData:file parameters:nil completion:completionBlock]; 515 | 516 | } 517 | 518 | - (NSURLSessionDataTask *) loadFileData:(BAAFile *)file parameters:(NSDictionary *)parameters completion:(void(^)(NSData *data, NSError *error))completionBlock { 519 | 520 | NSURLSession *s = [NSURLSession sharedSession]; 521 | NSString *path = [NSString stringWithFormat:@"file/%@", file.fileId]; 522 | BAAMutableURLRequest *request = [self requestWithMethod:@"GET" URLString:path parameters:parameters]; 523 | NSURLSessionDataTask *task = [s dataTaskWithRequest:request 524 | completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 525 | 526 | NSHTTPURLResponse *r = (NSHTTPURLResponse*)response; 527 | if (error == nil && r.statusCode == 200) { 528 | 529 | dispatch_async(dispatch_get_main_queue(), ^{ 530 | 531 | completionBlock(data, nil); 532 | 533 | }); 534 | 535 | 536 | 537 | } else { 538 | 539 | completionBlock(nil, error); 540 | 541 | } 542 | 543 | }]; 544 | 545 | [task resume]; 546 | return task; 547 | 548 | } 549 | 550 | - (void) uploadFile:(BAAFile *)file withPermissions:(NSDictionary *)permissions completion:(BAAObjectResultBlock)completionBlock { 551 | 552 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@/%@", self.baseURL, @"file"]]]; 553 | 554 | [request setHTTPMethod:@"POST"]; 555 | [request setValue:self.appCode forHTTPHeaderField:@"X-BAASBOX-APPCODE"]; 556 | [request setValue:self.currentUser.authenticationToken forHTTPHeaderField:@"X-BB-SESSION"]; 557 | 558 | NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]; 559 | [request addValue:contentType forHTTPHeaderField:@"Content-Type"]; 560 | 561 | NSMutableData *body = [NSMutableData data]; 562 | 563 | // image 564 | [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; 565 | [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"photo\"; filename=\"%@\"\r\n", [[NSUUID UUID] UUIDString]] 566 | dataUsingEncoding:NSUTF8StringEncoding]]; 567 | [body appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", file.contentType] dataUsingEncoding:NSUTF8StringEncoding]]; 568 | [body appendData:file.data]; 569 | 570 | // attachedData 571 | [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; 572 | NSError *err; 573 | NSData *attachedData = [NSJSONSerialization dataWithJSONObject:file.attachedData options:0 error:&err]; 574 | NSString* jsonString = [[NSString alloc] initWithBytes:[attachedData bytes] length:[attachedData length] encoding:NSUTF8StringEncoding]; 575 | [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"attachedData\"\r\n\r\n%@", jsonString] dataUsingEncoding:NSUTF8StringEncoding]]; 576 | [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; 577 | 578 | // ACL 579 | if (permissions) { 580 | 581 | NSData *aclData = [NSJSONSerialization dataWithJSONObject:permissions options:0 error:&err]; 582 | NSString *aclString = [[NSString alloc] initWithBytes:[aclData bytes] length:[aclData length] encoding:NSUTF8StringEncoding]; 583 | [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"acl\"\r\n\r\n%@", aclString] dataUsingEncoding:NSUTF8StringEncoding]]; 584 | [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; 585 | 586 | } 587 | 588 | [request setHTTPBody:body]; 589 | 590 | [[self.session dataTaskWithRequest:request 591 | completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 592 | 593 | if (completionBlock) { 594 | 595 | NSHTTPURLResponse *res = (NSHTTPURLResponse*)response; 596 | 597 | if (error == nil && res.statusCode <= 201) { 598 | 599 | NSDictionary *d = [NSJSONSerialization JSONObjectWithData:data 600 | options:kNilOptions 601 | error:nil]; 602 | id c = [file class]; 603 | id newObject = [[c alloc] initWithDictionary:d[@"data"]]; 604 | completionBlock(newObject, nil); 605 | 606 | } else { 607 | 608 | completionBlock(nil, error); 609 | 610 | } 611 | } 612 | 613 | }] resume]; 614 | 615 | } 616 | 617 | - (void) deleteFile:(BAAFile *)file completion:(BAABooleanResultBlock)completionBlock { 618 | 619 | NSString *path = [NSString stringWithFormat:@"file/%@", file.fileId]; 620 | [self deletePath:path 621 | parameters:nil 622 | success:^(id responseObject) { 623 | 624 | if (completionBlock) { 625 | 626 | NSString *res = responseObject[@"result"]; 627 | if ([res isEqualToString:@"ok"]) 628 | completionBlock(YES, nil); 629 | 630 | } 631 | 632 | } failure:^(NSError *error) { 633 | 634 | if (completionBlock) 635 | completionBlock(NO, error); 636 | 637 | }]; 638 | 639 | } 640 | 641 | - (void) loadFileDetails:(NSString *)fileID completion:(BAAObjectResultBlock)completionBlock { 642 | 643 | NSString *path = [NSString stringWithFormat:@"file/details/%@", fileID]; 644 | [self getPath:path 645 | parameters:nil 646 | success:^(id responseObject) { 647 | 648 | if (completionBlock) { 649 | BAAFile *file = [[BAAFile alloc] initWithDictionary:responseObject[@"data"]]; 650 | completionBlock (file, nil); 651 | } 652 | 653 | } failure:^(NSError *error) { 654 | 655 | if (completionBlock) { 656 | completionBlock(nil, error); 657 | } 658 | 659 | }]; 660 | 661 | } 662 | 663 | - (void) loadFilesAndDetailsWithCompletion:(BAAArrayResultBlock)completionBlock { 664 | 665 | 666 | [self getPath:@"file/details" 667 | parameters:nil 668 | success:^(NSDictionary *responseObject) { 669 | 670 | if (completionBlock) { 671 | 672 | NSArray *files = responseObject[@"data"]; 673 | NSMutableArray *resultArray = [NSMutableArray new]; 674 | 675 | for (NSDictionary *fileDictionary in files) { 676 | 677 | BAAFile *file = [[BAAFile alloc] initWithDictionary:fileDictionary]; 678 | [resultArray addObject:file]; 679 | 680 | } 681 | 682 | completionBlock(resultArray, nil); 683 | 684 | } 685 | 686 | } failure:^(NSError *error) { 687 | 688 | if (completionBlock) { 689 | completionBlock(nil, error); 690 | } 691 | 692 | }]; 693 | } 694 | 695 | #pragma mark - Acl 696 | 697 | - (void) grantAccess:(id)element toRole:(NSString *)roleName accessType:(NSString *)access completion:(BAAObjectResultBlock)completionBlock { 698 | 699 | NSString *path = [self buildPathForRoleACL:element forAccessType:access roleName:roleName]; 700 | 701 | [self putPath:path 702 | parameters:nil 703 | success:^(id responseObject) { 704 | 705 | if (completionBlock) { 706 | completionBlock(element, nil); 707 | } 708 | 709 | } failure:^(NSError *error) { 710 | 711 | if (completionBlock) { 712 | completionBlock(nil, error); 713 | } 714 | 715 | }]; 716 | 717 | } 718 | 719 | - (void) grantAccess:(id)element toUser:(NSString *)username accessType:(NSString *)access completion:(BAAObjectResultBlock)completionBlock { 720 | 721 | NSString *path = [self buildPathForUserACL:element forAccessType:access username:username]; 722 | 723 | [self putPath:path 724 | parameters:nil 725 | success:^(id responseObject) { 726 | 727 | if (completionBlock) { 728 | completionBlock(element, nil); 729 | } 730 | 731 | } failure:^(NSError *error) { 732 | 733 | if (completionBlock) { 734 | completionBlock(nil, error); 735 | } 736 | 737 | }]; 738 | 739 | } 740 | 741 | - (void) revokeAccess:(id)element toRole:(NSString *)roleName accessType:(NSString *)access completion:(BAAObjectResultBlock)completionBlock { 742 | 743 | NSString *path = [self buildPathForRoleACL:element forAccessType:access roleName:roleName]; 744 | 745 | [self deletePath:path 746 | parameters:nil 747 | success:^(id responseObject) { 748 | 749 | if (completionBlock) { 750 | completionBlock(element, nil); 751 | } 752 | 753 | } failure:^(NSError *error) { 754 | 755 | if (completionBlock) { 756 | completionBlock(nil, error); 757 | } 758 | 759 | }]; 760 | 761 | } 762 | 763 | - (void) revokeAccess:(id)element toUser:(NSString *)username accessType:(NSString *)access completion:(BAAObjectResultBlock)completionBlock { 764 | 765 | NSString *path = [self buildPathForUserACL:element forAccessType:access username:username]; 766 | 767 | [self deletePath:path 768 | parameters:nil 769 | success:^(id responseObject) { 770 | 771 | if (completionBlock) { 772 | completionBlock(element, nil); 773 | } 774 | 775 | } failure:^(NSError *error) { 776 | 777 | if (completionBlock) { 778 | completionBlock(nil, error); 779 | } 780 | 781 | }]; 782 | 783 | } 784 | 785 | 786 | // Both methods are ugly, but at the moment let's live with these 787 | - (NSString *) buildPathForRoleACL:(id)element forAccessType:(NSString *)accessType roleName:(NSString *)role { 788 | 789 | NSString *path; 790 | 791 | if ([element isKindOfClass:[BAAFile class]]) { 792 | 793 | BAAFile *file = (BAAFile *)element; 794 | path = [NSString stringWithFormat:@"file/%@/%@/role/%@", file.fileId, accessType, role]; 795 | 796 | } else { 797 | 798 | BAAObject *object = (BAAObject *)element; 799 | path = [NSString stringWithFormat:@"%@/%@/%@/role/%@", object.collectionName, object.objectId, accessType, role]; 800 | 801 | } 802 | 803 | return path; 804 | 805 | } 806 | 807 | - (NSString *) buildPathForUserACL:(id)element forAccessType:(NSString *)accessType username:(NSString *)name { 808 | 809 | NSString *path; 810 | 811 | if ([element isKindOfClass:[BAAFile class]]) { 812 | 813 | BAAFile *file = (BAAFile *)element; 814 | path = [NSString stringWithFormat:@"file/%@/%@/user/%@", file.fileId, accessType, name]; 815 | 816 | } else { 817 | 818 | BAAObject *object = (BAAObject *)element; 819 | path = [NSString stringWithFormat:@"%@/%@/%@/user/%@", object.collectionName, object.objectId, accessType, name]; 820 | 821 | } 822 | 823 | return path; 824 | 825 | } 826 | 827 | 828 | #pragma mark - User methods 829 | 830 | - (void) loadCurrentUserWithCompletion:(BAAObjectResultBlock)completionBlock { 831 | 832 | [self getPath:@"me" 833 | parameters:nil 834 | success:^(NSDictionary *responseObject) { 835 | 836 | [self updateUserWithDictionary:responseObject]; 837 | 838 | if (completionBlock) { 839 | completionBlock(self.currentUser, nil); 840 | } 841 | 842 | } failure:^(NSError *error) { 843 | 844 | if (completionBlock) { 845 | completionBlock(nil, error); 846 | } 847 | 848 | }]; 849 | 850 | } 851 | 852 | - (void) updateUserWithCompletion:(BAAObjectResultBlock)completionBlock { 853 | 854 | [self putPath:@"user" 855 | parameters:@{@"visibleByAnonymousUsers" : self.currentUser.visibleByAnonymousUsers, 856 | @"visibleByTheUser" : self.currentUser.visibleByTheUser, 857 | @"visibleByFriends" : self.currentUser.visibleByFriends, 858 | @"visibleByRegisteredUsers" : self.currentUser.visibleByRegisteredUsers} 859 | success:^(NSDictionary *responseObject) { 860 | 861 | [self updateUserWithDictionary:responseObject]; 862 | 863 | if (completionBlock) { 864 | completionBlock(self.currentUser, nil); 865 | } 866 | 867 | } failure:^(NSError *error) { 868 | 869 | if (completionBlock) { 870 | completionBlock(nil, error); 871 | } 872 | 873 | }]; 874 | 875 | } 876 | 877 | - (void) loadUsersDetails:(NSString *)userId completion:(BAAObjectResultBlock)completionBlock { 878 | 879 | [self getPath:[NSString stringWithFormat:@"user/%@", userId] 880 | parameters:nil 881 | success:^(id responseObject) { 882 | 883 | if (completionBlock) { 884 | BAAUser *user = [[BAAUser alloc] initWithDictionary:responseObject[@"data"]]; 885 | completionBlock(user, nil); 886 | } 887 | 888 | } failure:^(NSError *error) { 889 | 890 | if (completionBlock) { 891 | completionBlock(nil, error); 892 | } 893 | 894 | }]; 895 | 896 | } 897 | 898 | 899 | - (void) loadUsersWithCompletion:(BAAArrayResultBlock)completionBlock { 900 | 901 | [self loadUsersWithParameters:@{kPageNumberKey : @0, kPageSizeKey : @20} 902 | completion:completionBlock]; 903 | 904 | } 905 | 906 | - (void) loadUsersWithParameters:(NSDictionary *)parameters completion:(BAAArrayResultBlock)completionBlock { 907 | 908 | [self getPath:@"users" 909 | parameters:parameters 910 | success:^(id responseObject) { 911 | 912 | NSArray *objects = responseObject[@"data"]; 913 | NSMutableArray *users = [NSMutableArray array]; 914 | 915 | for (NSDictionary *d in objects) { 916 | 917 | BAAUser *u = [[BAAUser alloc] initWithDictionary:d]; 918 | [users addObject:u]; 919 | 920 | } 921 | 922 | if (completionBlock) { 923 | completionBlock(users, nil); 924 | } 925 | 926 | } failure:^(NSError *error) { 927 | 928 | if (completionBlock) { 929 | completionBlock(nil, error); 930 | } 931 | 932 | }]; 933 | 934 | } 935 | 936 | - (void) loadFollowingForUser:(BAAUser *)user completion:(BAAArrayResultBlock)completionBlock { 937 | 938 | [self getPath:[NSString stringWithFormat:@"following/%@", user.username] 939 | parameters:nil 940 | success:^(id responseObject) { 941 | 942 | if (completionBlock) { 943 | 944 | NSArray *users = responseObject[@"data"]; 945 | NSMutableArray *resultArray = [NSMutableArray array]; 946 | 947 | for (NSDictionary *d in users) { 948 | 949 | BAAUser *user = [[BAAUser alloc] initWithDictionary:d]; 950 | [resultArray addObject:user]; 951 | 952 | } 953 | 954 | completionBlock(resultArray, nil); 955 | 956 | } 957 | 958 | 959 | } failure:^(NSError *error) { 960 | 961 | if (completionBlock) { 962 | completionBlock(nil, error); 963 | } 964 | 965 | }]; 966 | 967 | } 968 | 969 | - (void) loadFollowersOfUser:(BAAUser *)user completion:(BAAArrayResultBlock)completionBlock { 970 | 971 | [self getPath:[NSString stringWithFormat:@"followers/%@", user.username] 972 | parameters:nil 973 | success:^(id responseObject) { 974 | 975 | if (completionBlock) { 976 | 977 | NSArray *users = responseObject[@"data"]; 978 | NSMutableArray *resultArray = [NSMutableArray array]; 979 | 980 | for (NSDictionary *d in users) { 981 | 982 | BAAUser *user = [[BAAUser alloc] initWithDictionary:d]; 983 | [resultArray addObject:user]; 984 | 985 | } 986 | 987 | completionBlock(resultArray, nil); 988 | 989 | } 990 | 991 | 992 | } failure:^(NSError *error) { 993 | 994 | if (completionBlock) { 995 | completionBlock(nil, error); 996 | } 997 | 998 | }]; 999 | 1000 | } 1001 | 1002 | - (void) followUser:(BAAUser *)user completion:(BAAObjectResultBlock)completionBlock { 1003 | 1004 | [self postPath:[NSString stringWithFormat:@"follow/%@", user.username] 1005 | parameters:nil 1006 | success:^(id responseObject) { 1007 | 1008 | if (completionBlock) { 1009 | 1010 | BAAUser *user = [[BAAUser alloc] initWithDictionary:responseObject[@"data"]]; 1011 | 1012 | if (user) { 1013 | 1014 | completionBlock(user, nil); 1015 | 1016 | } 1017 | 1018 | } 1019 | 1020 | 1021 | } failure:^(NSError *error) { 1022 | 1023 | if (completionBlock) { 1024 | completionBlock(nil, error); 1025 | } 1026 | 1027 | }]; 1028 | 1029 | } 1030 | 1031 | - (void) unfollowUser:(BAAUser *)user completion:(BAABooleanResultBlock)completionBlock { 1032 | 1033 | [self deletePath:[NSString stringWithFormat:@"follow/%@", user.username] 1034 | parameters:nil 1035 | success:^(id responseObject) { 1036 | 1037 | if (completionBlock) { 1038 | NSString *res = responseObject[@"result"]; 1039 | if ([res isEqualToString:@"ok"]) { 1040 | completionBlock(YES, nil); 1041 | } 1042 | } 1043 | 1044 | 1045 | } failure:^(NSError *error) { 1046 | 1047 | if (completionBlock) { 1048 | completionBlock(NO, error); 1049 | } 1050 | 1051 | }]; 1052 | 1053 | } 1054 | 1055 | - (void) changeOldPassword:(NSString *)oldPassword 1056 | toNewPassword:(NSString *)newPassword 1057 | completion:(BAABooleanResultBlock)completionBlock { 1058 | 1059 | [self putPath:@"me/password" 1060 | parameters:@{@"old": oldPassword, @"new": newPassword} 1061 | success:^(id responseObject) { 1062 | 1063 | if (completionBlock) { 1064 | 1065 | NSString *res = responseObject[@"result"]; 1066 | 1067 | if ([res isEqualToString:@"ok"]) { 1068 | 1069 | completionBlock(YES, nil); 1070 | 1071 | } else { 1072 | 1073 | NSDictionary *userInfo = @{ 1074 | NSLocalizedDescriptionKey: responseObject[@"message"], 1075 | NSLocalizedFailureReasonErrorKey: responseObject[@"message"], 1076 | NSLocalizedRecoverySuggestionErrorKey: responseObject[@"message"] 1077 | }; 1078 | NSError *error = [NSError errorWithDomain:[BaasBox errorDomain] 1079 | code:[BaasBox errorCode] 1080 | userInfo:userInfo]; 1081 | completionBlock(NO, error); 1082 | 1083 | } 1084 | } 1085 | 1086 | } failure:^(NSError *error) { 1087 | 1088 | if (completionBlock) { 1089 | completionBlock(NO, error); 1090 | } 1091 | 1092 | }]; 1093 | 1094 | } 1095 | 1096 | - (void) resetPasswordForUsername:(NSString *)username withCompletion:(BAABooleanResultBlock)completionBlock { 1097 | 1098 | NSString *path = [NSString stringWithFormat:@"user/%@/password/reset", username]; 1099 | [self getPath:path 1100 | parameters:nil 1101 | success:^(id responseObject) { 1102 | 1103 | if (completionBlock) { 1104 | 1105 | NSString *res = responseObject[@"result"]; 1106 | 1107 | if ([res isEqualToString:@"ok"]) { 1108 | 1109 | completionBlock(YES, nil); 1110 | 1111 | } else { 1112 | 1113 | NSDictionary *userInfo = @{ 1114 | NSLocalizedDescriptionKey: responseObject[@"message"], 1115 | NSLocalizedFailureReasonErrorKey: responseObject[@"message"], 1116 | NSLocalizedRecoverySuggestionErrorKey: responseObject[@"message"] 1117 | }; 1118 | NSError *error = [NSError errorWithDomain:[BaasBox errorDomain] 1119 | code:[BaasBox errorCode] 1120 | userInfo:userInfo]; 1121 | completionBlock(NO, error); 1122 | 1123 | } 1124 | } 1125 | 1126 | } failure:^(NSError *error) { 1127 | 1128 | if (completionBlock) { 1129 | completionBlock(NO, error); 1130 | } 1131 | 1132 | }]; 1133 | 1134 | } 1135 | 1136 | #pragma mark - Push notifications 1137 | 1138 | - (void) askToEnablePushNotifications { 1139 | 1140 | #if !(TARGET_IPHONE_SIMULATOR) 1141 | 1142 | #if TARGET_OS_IPHONE 1143 | 1144 | #if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 1145 | 1146 | [[UIApplication sharedApplication] registerForRemoteNotificationTypes: 1147 | (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)]; 1148 | 1149 | #else 1150 | 1151 | UIUserNotificationSettings *settings = 1152 | [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert |UIUserNotificationTypeBadge | UIUserNotificationTypeSound 1153 | categories:nil]; 1154 | [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; 1155 | [[UIApplication sharedApplication] registerForRemoteNotifications]; 1156 | 1157 | #endif 1158 | 1159 | #else 1160 | 1161 | [[NSApplication sharedApplication] registerForRemoteNotificationTypes: 1162 | (NSRemoteNotificationTypeBadge | NSRemoteNotificationTypeSound | NSRemoteNotificationTypeAlert)]; 1163 | 1164 | #endif 1165 | 1166 | #endif 1167 | 1168 | } 1169 | 1170 | - (void) enablePushNotifications:(NSData *)tokenData completion:(BAABooleanResultBlock)completionBlock { 1171 | 1172 | if (self.currentUser.pushEnabled) { 1173 | if (completionBlock) { 1174 | completionBlock(YES, nil); 1175 | return; 1176 | } 1177 | } 1178 | 1179 | self.currentUser.pushNotificationToken = [self convertTokenToDeviceID:tokenData]; 1180 | 1181 | NSString *path = [NSString stringWithFormat:@"push/enable/%@/%@", @"ios", self.currentUser.pushNotificationToken]; 1182 | 1183 | [self putPath:path 1184 | parameters:nil 1185 | success:^(id responseObject) { 1186 | 1187 | if (completionBlock) { 1188 | 1189 | if (responseObject) { 1190 | 1191 | self.currentUser.pushEnabled = YES; 1192 | completionBlock(YES, nil); 1193 | 1194 | } else { 1195 | 1196 | NSMutableDictionary* details = [NSMutableDictionary dictionary]; 1197 | details[@"NSLocalizedDescriptionKey"] = [NSString stringWithFormat:@"Server returned %@", responseObject]; 1198 | NSError *error = [NSError errorWithDomain:[BaasBox errorDomain] 1199 | code:[BaasBox errorCode] 1200 | userInfo:details]; 1201 | completionBlock(NO, error); 1202 | 1203 | } 1204 | 1205 | } 1206 | 1207 | } failure:^(NSError *error) { 1208 | 1209 | if (completionBlock) { 1210 | completionBlock(NO, error); 1211 | } 1212 | 1213 | }]; 1214 | 1215 | } 1216 | 1217 | - (void) disablePushNotificationsWithCompletion:(BAABooleanResultBlock)completionBlock { 1218 | 1219 | if (!self.currentUser.pushEnabled) { 1220 | 1221 | if (completionBlock) { 1222 | 1223 | NSMutableDictionary* details = [NSMutableDictionary dictionary]; 1224 | details[@"NSLocalizedDescriptionKey"] = @"Push notifications already disabled"; 1225 | NSError *error = [NSError errorWithDomain:[BaasBox errorDomain] 1226 | code:[BaasBox errorCode] 1227 | userInfo:details]; 1228 | completionBlock(NO, error); 1229 | 1230 | } 1231 | 1232 | return; 1233 | } 1234 | 1235 | NSString *path = [NSString stringWithFormat:@"push/disable/%@", self.currentUser.pushNotificationToken]; 1236 | 1237 | [self putPath:path 1238 | parameters:nil 1239 | success:^(id responseObject) { 1240 | 1241 | if (completionBlock) { 1242 | 1243 | if (responseObject) { 1244 | 1245 | self.currentUser.pushEnabled = YES; 1246 | completionBlock(YES, nil); 1247 | 1248 | } else { 1249 | 1250 | NSMutableDictionary* details = [NSMutableDictionary dictionary]; 1251 | details[@"NSLocalizedDescriptionKey"] = [NSString stringWithFormat:@"Server returned %@", responseObject]; 1252 | NSError *error = [NSError errorWithDomain:[BaasBox errorDomain] 1253 | code:[BaasBox errorCode] 1254 | userInfo:details]; 1255 | completionBlock(NO, error); 1256 | 1257 | } 1258 | 1259 | } 1260 | 1261 | } failure:^(NSError *error) { 1262 | 1263 | if (completionBlock) { 1264 | completionBlock(NO, error); 1265 | } 1266 | 1267 | }]; 1268 | 1269 | } 1270 | 1271 | - (NSString *)convertTokenToDeviceID:(NSData *)token { 1272 | 1273 | NSMutableString *deviceID = [NSMutableString string]; 1274 | 1275 | unsigned char *ptr = (unsigned char *)[token bytes]; 1276 | 1277 | for (NSInteger i=0; i < 32; ++i) { 1278 | [deviceID appendString:[NSString stringWithFormat:@"%02x", ptr[i]]]; 1279 | } 1280 | 1281 | return deviceID; 1282 | } 1283 | 1284 | - (void)pushNotificationToUsername:(NSString *)username 1285 | withMessage:(NSString *)message 1286 | completion:(BAABooleanResultBlock)completionBlock { 1287 | 1288 | [self pushNotificationToUsername:username 1289 | withMessage:message 1290 | customPayload:nil 1291 | completion:completionBlock]; 1292 | } 1293 | 1294 | - (void)pushNotificationToUsername:(NSString *)username 1295 | withMessage:(NSString *)message 1296 | customPayload:(NSDictionary *)customPayload 1297 | completion:(BAABooleanResultBlock)completionBlock { 1298 | 1299 | NSString *path = [NSString stringWithFormat:@"/push/message/%@", username]; 1300 | NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithObject:message forKey:kPushNotificationMessageKey]; 1301 | 1302 | if (customPayload) { 1303 | [parameters setObject:customPayload forKey:kPushNotificationCustomPayloadKey]; 1304 | } 1305 | 1306 | BAAClient *client = [BAAClient sharedClient]; 1307 | [client postPath:path 1308 | parameters:parameters 1309 | success:^(id responseObject) { 1310 | 1311 | if (completionBlock) { 1312 | completionBlock(YES, nil); 1313 | } 1314 | 1315 | } failure:^(NSError *error) { 1316 | 1317 | if (completionBlock) { 1318 | completionBlock(NO, error); 1319 | } 1320 | 1321 | }]; 1322 | } 1323 | 1324 | #pragma mark - Admin 1325 | 1326 | - (void) createCollection:(NSString *)collectionName completion:(BAAObjectResultBlock)completionBlock { 1327 | 1328 | [self postPath:[NSString stringWithFormat:@"admin/collection/%@", collectionName] 1329 | parameters:nil 1330 | success:^(id responseObject) { 1331 | 1332 | if (completionBlock) { 1333 | 1334 | completionBlock(responseObject, nil); 1335 | 1336 | } 1337 | 1338 | } failure:^(NSError *error) { 1339 | 1340 | if (completionBlock) { 1341 | 1342 | completionBlock(nil, error); 1343 | 1344 | } 1345 | 1346 | }]; 1347 | 1348 | } 1349 | 1350 | - (void) loadSettingsWithCompletion:(BAAObjectResultBlock)completionBlock { 1351 | 1352 | [self getPath:@"admin/configuration/dump.json" 1353 | parameters:nil 1354 | success:^(NSDictionary *responseObject) { 1355 | 1356 | if (completionBlock) { 1357 | completionBlock(responseObject, nil); 1358 | } 1359 | 1360 | } failure:^(NSError *error) { 1361 | 1362 | if (completionBlock) { 1363 | completionBlock(nil, error); 1364 | } 1365 | 1366 | }]; 1367 | 1368 | } 1369 | 1370 | - (void) loadSettingsSection:(NSString *)sectionName completion:(BAAObjectResultBlock)completionBlock { 1371 | 1372 | NSString *path = [NSString stringWithFormat:@"admin/configuration/%@", sectionName]; 1373 | [self getPath:path 1374 | parameters:nil 1375 | success:^(NSDictionary *responseObject) { 1376 | 1377 | if (completionBlock) { 1378 | completionBlock(responseObject, nil); 1379 | } 1380 | 1381 | } failure:^(NSError *error) { 1382 | 1383 | if (completionBlock) { 1384 | completionBlock(nil, error); 1385 | } 1386 | 1387 | }]; 1388 | 1389 | } 1390 | 1391 | - (void) setValue:(NSString *)value forKey:(NSString *)key inSection:(NSString *)sectionName completion:(BAAObjectResultBlock)completionBlock { 1392 | 1393 | NSString *path = [NSString stringWithFormat:@"admin/configuration/%@/%@/%@", sectionName, key, value]; 1394 | [self putPath:path 1395 | parameters:nil 1396 | success:^(NSDictionary *responseObject) { 1397 | 1398 | if (completionBlock) { 1399 | completionBlock(responseObject, nil); 1400 | } 1401 | 1402 | } failure:^(NSError *error) { 1403 | 1404 | if (completionBlock) { 1405 | completionBlock(nil, error); 1406 | } 1407 | 1408 | }]; 1409 | 1410 | } 1411 | 1412 | #pragma mark - URL Serialization 1413 | 1414 | - (BAAMutableURLRequest *)requestWithMethod:(NSString *)method 1415 | URLString:(NSString *)path 1416 | parameters:(NSDictionary *)parameters { 1417 | 1418 | NSString *u = [[NSURL URLWithString:path relativeToURL:self.baseURL] absoluteString]; 1419 | NSURL *url = [NSURL URLWithString:u]; 1420 | BAAMutableURLRequest *request = [[BAAMutableURLRequest alloc] initWithURL:url]; 1421 | 1422 | if ([path isEqualToString:@"login"]) { // Hack. Login should support json 1423 | 1424 | request.contentType = BAAContentTypeForm; 1425 | 1426 | } 1427 | 1428 | [request setHTTPMethod:method]; 1429 | [request setValue:self.appCode 1430 | forHTTPHeaderField:@"X-BAASBOX-APPCODE"]; 1431 | [request setValue:self.currentUser.authenticationToken 1432 | forHTTPHeaderField:@"X-BB-SESSION"]; 1433 | 1434 | request = [[self requestBySerializingRequest:request withParameters:parameters error:nil] mutableCopy]; 1435 | 1436 | return request; 1437 | } 1438 | 1439 | - (BAAMutableURLRequest *)requestBySerializingRequest:(BAAMutableURLRequest *)mutableRequest 1440 | withParameters:(id)parameters 1441 | error:(NSError *__autoreleasing *)error { 1442 | 1443 | if (!parameters) { 1444 | return mutableRequest; 1445 | } 1446 | 1447 | NSString *charset = (__bridge NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)); 1448 | NSString *query = BAAQueryStringFromParametersWithEncoding(parameters, NSUTF8StringEncoding); 1449 | 1450 | if (mutableRequest.contentType == BAAContentTypeForm) { 1451 | 1452 | [mutableRequest setHTTPBody:[query dataUsingEncoding:NSUTF8StringEncoding]]; 1453 | [mutableRequest setValue:[NSString stringWithFormat:@"application/x-www-form-urlencoded; charset=%@", charset] 1454 | forHTTPHeaderField:@"Content-Type"]; 1455 | 1456 | } else { 1457 | 1458 | [mutableRequest setValue:[NSString stringWithFormat:@"application/json; charset=%@", charset] 1459 | forHTTPHeaderField:@"Content-Type"]; 1460 | if ([mutableRequest.HTTPMethod isEqualToString:@"POST"] || [mutableRequest.HTTPMethod isEqualToString:@"PUT"] || [mutableRequest.HTTPMethod isEqualToString:@"DELETE"]) { 1461 | [mutableRequest setHTTPBody:[NSJSONSerialization dataWithJSONObject:parameters options:0 error:error]]; 1462 | } 1463 | if ([mutableRequest.HTTPMethod isEqualToString:@"GET"]) { 1464 | mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]]; 1465 | } 1466 | 1467 | } 1468 | 1469 | return mutableRequest; 1470 | } 1471 | 1472 | #pragma mark - Client methods 1473 | 1474 | - (void)getPath:(NSString *)path 1475 | parameters:(NSDictionary *)parameters 1476 | success:(void (^)(id responseObject))success 1477 | failure:(void (^)(NSError *error))failure { 1478 | 1479 | BAAMutableURLRequest *request = [self requestWithMethod:@"GET" URLString:path parameters:parameters]; 1480 | 1481 | [[self.session dataTaskWithRequest:request 1482 | completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 1483 | 1484 | NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; 1485 | NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data 1486 | options:kNilOptions 1487 | error:nil]; 1488 | 1489 | if (httpResponse.statusCode >= 400) { 1490 | 1491 | NSError *error = [BaasBox authenticationErrorForResponse:jsonObject]; 1492 | failure(error); 1493 | [[NSNotificationCenter defaultCenter] postNotificationName:kAuthenticationTokenExpiredNotification 1494 | object:nil]; 1495 | return; 1496 | 1497 | } 1498 | 1499 | if (error == nil) { 1500 | 1501 | NSString *contentType = [httpResponse.allHeaderFields objectForKey:@"Content-type"]; 1502 | if ([contentType hasPrefix:@"image/"]) { 1503 | 1504 | success(data); 1505 | 1506 | } else { 1507 | 1508 | success(jsonObject); 1509 | 1510 | } 1511 | 1512 | } else { 1513 | 1514 | failure(error); 1515 | 1516 | } 1517 | 1518 | }] resume]; 1519 | 1520 | } 1521 | 1522 | - (void)postPath:(NSString *)path 1523 | parameters:(NSDictionary *)parameters 1524 | success:(void (^)(id responseObject))success 1525 | failure:(void (^)(NSError *error))failure { 1526 | 1527 | BAAMutableURLRequest *request = [self requestWithMethod:@"POST" 1528 | URLString:path 1529 | parameters:parameters]; 1530 | 1531 | [[self.session dataTaskWithRequest:request 1532 | completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 1533 | 1534 | NSHTTPURLResponse *r = (NSHTTPURLResponse*)response; 1535 | NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data 1536 | options:kNilOptions 1537 | error:nil]; 1538 | 1539 | if (r.statusCode >= 400) { 1540 | 1541 | NSError *error = [BaasBox authenticationErrorForResponse:jsonObject]; 1542 | failure(error); 1543 | [[NSNotificationCenter defaultCenter] postNotificationName:kAuthenticationTokenExpiredNotification 1544 | object:nil]; 1545 | return; 1546 | 1547 | } 1548 | 1549 | if (error == nil) { 1550 | 1551 | success(jsonObject); 1552 | 1553 | } else { 1554 | 1555 | failure(error); 1556 | 1557 | } 1558 | 1559 | }] resume]; 1560 | 1561 | } 1562 | 1563 | - (void)putPath:(NSString *)path 1564 | parameters:(NSDictionary *)parameters 1565 | success:(void (^)(id responseObject))success 1566 | failure:(void (^)(NSError *error))failure { 1567 | 1568 | BAAMutableURLRequest *request = [self requestWithMethod:@"PUT" 1569 | URLString:path 1570 | parameters:parameters]; 1571 | [[self.session dataTaskWithRequest:request 1572 | completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 1573 | 1574 | NSHTTPURLResponse *r = (NSHTTPURLResponse*)response; 1575 | NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data 1576 | options:kNilOptions 1577 | error:nil]; 1578 | 1579 | if (r.statusCode >= 400) { 1580 | 1581 | NSError *error = [BaasBox authenticationErrorForResponse:jsonObject]; 1582 | failure(error); 1583 | [[NSNotificationCenter defaultCenter] postNotificationName:kAuthenticationTokenExpiredNotification 1584 | object:nil]; 1585 | return; 1586 | 1587 | } 1588 | 1589 | if (error == nil) { 1590 | 1591 | success(jsonObject); 1592 | 1593 | } else { 1594 | 1595 | failure(error); 1596 | 1597 | } 1598 | 1599 | }] resume]; 1600 | 1601 | } 1602 | 1603 | - (void)deletePath:(NSString *)path 1604 | parameters:(NSDictionary *)parameters 1605 | success:(void (^)(id responseObject))success 1606 | failure:(void (^)(NSError *error))failure { 1607 | 1608 | BAAMutableURLRequest *request = [self requestWithMethod:@"DELETE" 1609 | URLString:path 1610 | parameters:parameters]; 1611 | [[self.session dataTaskWithRequest:request 1612 | completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 1613 | 1614 | NSHTTPURLResponse *r = (NSHTTPURLResponse*)response; 1615 | NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:data 1616 | options:kNilOptions 1617 | error:nil]; 1618 | 1619 | if (r.statusCode >= 400) { 1620 | 1621 | NSError *error = [BaasBox authenticationErrorForResponse:jsonObject]; 1622 | failure(error); 1623 | [[NSNotificationCenter defaultCenter] postNotificationName:kAuthenticationTokenExpiredNotification 1624 | object:nil]; 1625 | return; 1626 | 1627 | } 1628 | 1629 | if (error == nil) { 1630 | 1631 | success(jsonObject); 1632 | 1633 | } else { 1634 | 1635 | failure(error); 1636 | 1637 | } 1638 | 1639 | }] resume]; 1640 | 1641 | } 1642 | 1643 | 1644 | #pragma mark - Helpers 1645 | 1646 | - (void) saveUserToDisk:(BAAUser *)user { 1647 | 1648 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 1649 | NSData *encodedUser = [NSKeyedArchiver archivedDataWithRootObject:user]; 1650 | [defaults setValue:encodedUser forKey:BAAUserKeyForUserDefaults]; 1651 | [defaults synchronize]; 1652 | 1653 | } 1654 | 1655 | - (BAAUser *) loadUserFromDisk { 1656 | 1657 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 1658 | NSData *decodedUser = [defaults objectForKey:BAAUserKeyForUserDefaults]; 1659 | 1660 | if (decodedUser) { 1661 | 1662 | BAAUser *user = (BAAUser *)[NSKeyedUnarchiver unarchiveObjectWithData:decodedUser]; 1663 | return user; 1664 | 1665 | } else { 1666 | 1667 | return nil; 1668 | 1669 | } 1670 | 1671 | 1672 | } 1673 | 1674 | - (void) updateUserWithDictionary:(NSDictionary *)dictionary { 1675 | 1676 | NSDictionary *dataDictionary = dictionary[@"data"]; 1677 | self.currentUser.roles = dataDictionary[@"user"][@"roles"]; 1678 | self.currentUser.status = dataDictionary[@"user"][@"status"]; 1679 | 1680 | self.currentUser.visibleByAnonymousUsers = [NSMutableDictionary dictionaryWithDictionary:dataDictionary[@"visibleByAnonymousUsers"]]; 1681 | self.currentUser.visibleByRegisteredUsers = [NSMutableDictionary dictionaryWithDictionary:dataDictionary[@"visibleByRegisteredUsers"]]; 1682 | 1683 | if (dictionary[@"visibleByFriends"] == [NSNull null]) { 1684 | 1685 | self.currentUser.visibleByFriends = [NSMutableDictionary dictionary]; 1686 | 1687 | } else { 1688 | 1689 | self.currentUser.visibleByFriends = [NSMutableDictionary dictionaryWithDictionary:dataDictionary[@"visibleByFriends"]]; 1690 | 1691 | } 1692 | 1693 | if (dictionary[@"visibleByTheUser"] == [NSNull null]) { 1694 | 1695 | self.currentUser.visibleByTheUser = [NSMutableDictionary dictionary]; 1696 | 1697 | } else { 1698 | 1699 | self.currentUser.visibleByTheUser = [NSMutableDictionary dictionaryWithDictionary:dataDictionary[@"visibleByTheUser"]]; 1700 | 1701 | } 1702 | 1703 | [self saveUserToDisk:self.currentUser]; 1704 | 1705 | } 1706 | 1707 | - (BOOL) isAuthenticated { 1708 | 1709 | return self.currentUser.authenticationToken != nil; 1710 | 1711 | } 1712 | 1713 | @end 1714 | -------------------------------------------------------------------------------- /BaasBox-iOS-SDK/BAAFile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014. BaasBox 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and limitations under the License. 14 | */ 15 | 16 | #import 17 | #import "BAAClient.h" 18 | 19 | @interface BAAFile : NSObject 20 | 21 | @property (nonatomic, copy, readonly) NSData *data; 22 | @property (nonatomic, copy) NSString *fileId; 23 | @property (nonatomic, copy) NSString *author; 24 | @property (nonatomic, copy) NSString *contentType; 25 | @property (nonatomic, copy) NSString *creationDate; 26 | @property (nonatomic, strong) NSMutableDictionary *attachedData; 27 | @property (nonatomic, strong) NSMutableDictionary *metadataData; 28 | 29 | - (instancetype) initWithData:(NSData *)data; 30 | - (instancetype) initWithDictionary:(NSDictionary *)dictionary; 31 | 32 | + (void) getFilesWithCompletion:(BAAArrayResultBlock)completionBlock; 33 | - (NSURL *) fileURL; 34 | + (void) loadFileWithId:(NSString *)fileId completion:(void(^)(NSData *data, NSError *error))completionBlock; 35 | - (void) loadFileWithCompletion:(void(^)(NSData *data, NSError *error))completionBlock; 36 | - (void) loadFileWithParameters:(NSDictionary *)parameters completion:(void(^)(NSData *data, NSError *error))completionBlock; 37 | + (void) loadFileDetails:(NSString *)fileId completion:(BAAObjectResultBlock)completionBlock; 38 | + (void) loadFilesAndDetailsWithCompletion:(BAAArrayResultBlock)completionBlock; 39 | - (void) stopFileLoading; 40 | - (void) uploadFileWithPermissions:(NSDictionary *)permissions completion:(BAAObjectResultBlock)completionBlock; 41 | - (void) grantAccessToRole:(NSString *)roleName ofType:(NSString *)accessType completion:(BAAObjectResultBlock)completionBlock; 42 | - (void) grantAccessToUser:(NSString *)username ofType:(NSString *)accessType completion:(BAAObjectResultBlock)completionBlock; 43 | - (void) revokeAccessToRole:(NSString *)roleName ofType:(NSString *)accessType completion:(BAAObjectResultBlock)completionBlock; 44 | - (void) revokeAccessToUser:(NSString *)username ofType:(NSString *)accessType completion:(BAAObjectResultBlock)completionBlock; 45 | - (void) deleteFileWithCompletion:(BAABooleanResultBlock)completionBlock; 46 | + (void) deleteFileWithId:(NSString *)fileId completion:(BAABooleanResultBlock)completionBlock; 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /BaasBox-iOS-SDK/BAAFile.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014. BaasBox 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and limitations under the License. 14 | */ 15 | 16 | #import "BAAFile.h" 17 | 18 | @interface BAAFile () 19 | 20 | @property (nonatomic, copy) NSURL *fileURL; 21 | @property (nonatomic, strong) NSURLSessionDataTask *downloadTask; 22 | @property (nonatomic, strong) BAAClient *client; 23 | 24 | @end 25 | 26 | @implementation BAAFile 27 | 28 | - (instancetype) initWithDictionary:(NSDictionary *)dictionary { 29 | 30 | self = [super init]; 31 | 32 | if (self) { 33 | 34 | _fileId = dictionary[@"id"]; 35 | _author = dictionary[@"_author"]; 36 | _contentType = dictionary[@"contentType"]; 37 | _creationDate = dictionary[@"_creation_date"]; 38 | _attachedData = dictionary[@"attachedData"]; 39 | _metadataData = dictionary[@"metadata"]; 40 | 41 | } 42 | 43 | return self; 44 | 45 | } 46 | 47 | -(instancetype)initWithData:(NSData *)data { 48 | 49 | self = [super init]; 50 | 51 | if (self) { 52 | 53 | _data = data; 54 | 55 | } 56 | 57 | return self; 58 | 59 | } 60 | 61 | - (BAAClient *) client { 62 | 63 | if (_client == nil) 64 | _client = [BAAClient sharedClient]; 65 | 66 | return _client; 67 | 68 | } 69 | 70 | - (NSMutableDictionary *) attachedData { 71 | if (_attachedData == nil) 72 | _attachedData = [NSMutableDictionary dictionary]; 73 | 74 | return _attachedData; 75 | 76 | } 77 | 78 | + (void) getFilesWithCompletion:(BAAArrayResultBlock)completionBlock { 79 | 80 | BAAClient *client = [BAAClient sharedClient]; 81 | [client loadFiles:[[self alloc] init] 82 | completion:completionBlock]; 83 | 84 | } 85 | 86 | - (NSURL *) fileURL { 87 | 88 | if (self.fileId == nil) 89 | return nil; 90 | 91 | NSString *URLString = [NSString stringWithFormat:@"%@/file/%@", self.client.baseURL, self.fileId]; 92 | return [NSURL URLWithString:URLString]; 93 | 94 | } 95 | 96 | + (void) loadFileWithId:(NSString *)fileId completion:(void(^)(NSData *data, NSError *error))completionBlock { 97 | 98 | if (fileId && completionBlock) { 99 | 100 | BAAFile *file = [[BAAFile alloc] init]; 101 | file.fileId = fileId; 102 | [file loadFileWithCompletion:completionBlock]; 103 | 104 | } 105 | } 106 | 107 | - (void) loadFileWithCompletion:(void(^)(NSData *data, NSError *error))completionBlock { 108 | 109 | self.downloadTask = [self.client loadFileData:self 110 | completion:^(NSData *data, NSError *error) { 111 | 112 | if (completionBlock) { 113 | completionBlock(data, error); 114 | } 115 | 116 | }]; 117 | 118 | } 119 | 120 | - (void) loadFileWithParameters:(NSDictionary *)parameters completion:(void(^)(NSData *data, NSError *error))completionBlock { 121 | 122 | self.downloadTask = [self.client loadFileData:self 123 | parameters:parameters 124 | completion:^(NSData *data, NSError *error) { 125 | 126 | if (completionBlock) { 127 | completionBlock(data, error); 128 | } 129 | 130 | }]; 131 | 132 | } 133 | 134 | - (void) stopFileLoading { 135 | 136 | [self.downloadTask suspend]; 137 | 138 | } 139 | 140 | + (void) loadFileDetails:(NSString *)fileId completion:(BAAObjectResultBlock)completionBlock { 141 | 142 | BAAClient *client = [BAAClient sharedClient]; 143 | [client loadFileDetails:fileId 144 | completion:^(id object, NSError *error) { 145 | 146 | if (completionBlock) 147 | completionBlock(object, error); 148 | 149 | }]; 150 | 151 | } 152 | 153 | + (void) loadFilesAndDetailsWithCompletion:(BAAArrayResultBlock)completionBlock { 154 | 155 | BAAClient *client = [BAAClient sharedClient]; 156 | [client loadFilesAndDetailsWithCompletion:^(NSArray *files, NSError *error) { 157 | 158 | if (completionBlock) 159 | completionBlock(files, error); 160 | 161 | }]; 162 | 163 | } 164 | 165 | #pragma mark - ACL 166 | 167 | - (void) grantAccessToRole:(NSString *)roleName ofType:(NSString *)accessType completion:(BAAObjectResultBlock)completionBlock { 168 | 169 | [self.client grantAccess:self 170 | toRole:roleName 171 | accessType:accessType 172 | completion:completionBlock]; 173 | 174 | } 175 | 176 | - (void) grantAccessToUser:(NSString *)username ofType:(NSString *)accessType completion:(BAAObjectResultBlock)completionBlock { 177 | 178 | [self.client grantAccess:self 179 | toUser:username 180 | accessType:accessType 181 | completion:completionBlock]; 182 | 183 | } 184 | 185 | - (void) revokeAccessToRole:(NSString *)roleName ofType:(NSString *)accessType completion:(BAAObjectResultBlock)completionBlock { 186 | 187 | [self.client revokeAccess:self 188 | toRole:roleName 189 | accessType:accessType 190 | completion:completionBlock]; 191 | 192 | } 193 | 194 | - (void) revokeAccessToUser:(NSString *)username ofType:(NSString *)accessType completion:(BAAObjectResultBlock)completionBlock { 195 | 196 | [self.client revokeAccess:self 197 | toUser:username 198 | accessType:accessType 199 | completion:completionBlock]; 200 | 201 | } 202 | 203 | #pragma mark - Upload 204 | 205 | - (void) uploadFileWithPermissions:(NSDictionary *)permissions completion:(BAAObjectResultBlock)completionBlock; { 206 | 207 | [self.client uploadFile:self 208 | withPermissions:permissions 209 | completion:completionBlock]; 210 | 211 | 212 | } 213 | 214 | #pragma mark - Delete 215 | 216 | - (void) deleteFileWithCompletion:(BAABooleanResultBlock)completionBlock { 217 | 218 | [self.client deleteFile:self 219 | completion:completionBlock]; 220 | 221 | } 222 | 223 | + (void)deleteFileWithId:(NSString *)fileId completion:(BAABooleanResultBlock)completionBlock { 224 | 225 | if (fileId && completionBlock) { 226 | 227 | BAAFile *file = [[BAAFile alloc] init]; 228 | file.fileId = fileId; 229 | [file deleteFileWithCompletion:completionBlock]; 230 | 231 | } 232 | } 233 | 234 | @end 235 | -------------------------------------------------------------------------------- /BaasBox-iOS-SDK/BAAGlobals.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014. BaasBox 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and limitations under the License. 14 | */ 15 | 16 | 17 | 18 | #import 19 | 20 | typedef void (^BAAArrayResultBlock)(NSArray *objects, NSError *error); 21 | typedef void (^BAAObjectResultBlock)(id object, NSError *error); 22 | typedef void (^BAABooleanResultBlock)(BOOL success, NSError *error); 23 | typedef void (^BAAIntegerResultBlock)(NSInteger count, NSError *error); 24 | 25 | @interface BAAGlobals : NSObject 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /BaasBox-iOS-SDK/BAAGlobals.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014. BaasBox 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and limitations under the License. 14 | */ 15 | 16 | #import "BAAGlobals.h" 17 | 18 | @implementation BAAGlobals 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /BaasBox-iOS-SDK/BAAMutableURLRequest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014. BaasBox 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and limitations under the License. 14 | */ 15 | 16 | #import 17 | 18 | typedef NS_ENUM(NSUInteger, BAAContentType) { 19 | BAAContentTypeJSON, 20 | BAAContentTypeForm 21 | }; 22 | 23 | @interface BAAMutableURLRequest : NSMutableURLRequest 24 | 25 | @property (assign) BAAContentType contentType; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /BaasBox-iOS-SDK/BAAMutableURLRequest.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014. BaasBox 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and limitations under the License. 14 | */ 15 | 16 | #import "BAAMutableURLRequest.h" 17 | 18 | @implementation BAAMutableURLRequest 19 | 20 | -(id) init { 21 | self = [super init]; 22 | 23 | if (self) { 24 | _contentType = BAAContentTypeJSON; 25 | } 26 | 27 | return self; 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /BaasBox-iOS-SDK/BAAObject.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014. BaasBox 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and limitations under the License. 14 | */ 15 | 16 | #import 17 | #import "BAAGlobals.h" 18 | 19 | @interface BAAObject : NSObject 20 | 21 | @property (nonatomic, copy, readonly) NSString *objectId; 22 | @property (nonatomic, assign, readonly) NSInteger version; 23 | @property (nonatomic, strong, readonly) NSDate *creationDate; 24 | @property (nonatomic, strong, readonly) NSDictionary *acl; 25 | 26 | - (instancetype) initWithDictionary:(NSDictionary *)dictionary __attribute((objc_designated_initializer)); // Will be NS_DESIGNATED_INITIALIZER in Xcode6 27 | 28 | + (void) getObjectsWithCompletion:(BAAArrayResultBlock)completionBlock; 29 | + (void) getObjectsWithParams:(NSDictionary *)parameters completion:(BAAArrayResultBlock)completionBlock; 30 | + (void) getObjectWithId:(NSString *)objectID completion:(BAAObjectResultBlock)completionBlock; 31 | - (void) saveObjectWithCompletion:(BAAObjectResultBlock)completionBlock; 32 | - (void) saveObjectWithACL:(NSDictionary *)acl completion:(BAAObjectResultBlock)completionBlock; 33 | - (void) deleteObjectWithCompletion:(BAABooleanResultBlock)completionBlock; 34 | - (void) grantAccessToRole:(NSString *)roleName ofType:(NSString *)accessType completion:(BAAObjectResultBlock)completionBlock; 35 | - (void) grantAccessToUser:(NSString *)username ofType:(NSString *)accessType completion:(BAAObjectResultBlock)completionBlock; 36 | - (void) revokeAccessToRole:(NSString *)roleName ofType:(NSString *)accessType completion:(BAAObjectResultBlock)completionBlock; 37 | - (void) revokeAccessToUser:(NSString *)username ofType:(NSString *)accessType completion:(BAAObjectResultBlock)completionBlock; 38 | + (void) fetchCountForObjectsWithCompletion:(BAAIntegerResultBlock)completionBlock; 39 | + (NSString *) assetsEndPoint; 40 | - (NSString *) collectionName; 41 | - (NSDictionary*) objectAsDictionary; 42 | - (NSString *) jsonString; 43 | 44 | - (NSArray *)exclude; 45 | 46 | // Experimental 47 | + (void) getRandomObjectsWithParams:(NSDictionary *)parameters bound:(NSInteger)bound completion:(BAAArrayResultBlock)completionBlock; 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /BaasBox-iOS-SDK/BAAObject.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014. BaasBox 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and limitations under the License. 14 | */ 15 | 16 | #import "BAAObject.h" 17 | #import "BAAClient.h" 18 | #import "BaasBox.h" 19 | #import 20 | 21 | @interface BAAObject () 22 | 23 | @property (nonatomic, strong) BAAClient *client; 24 | 25 | @end 26 | 27 | @implementation BAAObject 28 | 29 | - (instancetype) initWithDictionary:(NSDictionary *)dictionary { 30 | 31 | self = [super init]; 32 | 33 | if (self) { 34 | 35 | _objectId = dictionary[@"id"]; 36 | _version = [dictionary[@"@version"] intValue]; 37 | _creationDate = [[BaasBox dateFormatter] dateFromString:dictionary[@"_creation_date"]]; 38 | 39 | } 40 | 41 | return self; 42 | 43 | } 44 | 45 | - (BAAClient *) client { 46 | 47 | if (_client == nil) 48 | _client = [BAAClient sharedClient]; 49 | 50 | return _client; 51 | 52 | } 53 | 54 | + (void) getObjectsWithCompletion:(BAAArrayResultBlock)completionBlock { 55 | 56 | BAAClient *client = [BAAClient sharedClient]; 57 | [client loadCollection:[[self alloc] init] 58 | completion:completionBlock]; 59 | 60 | } 61 | 62 | + (void) getObjectsWithParams:(NSDictionary *)parameters completion:(BAAArrayResultBlock)completionBlock { 63 | 64 | BAAClient *client = [BAAClient sharedClient]; 65 | [client loadCollection:[[self alloc] init] 66 | withParams:parameters 67 | completion:completionBlock]; 68 | 69 | } 70 | 71 | + (void) getObjectWithId:(NSString *)objectID completion:(BAAObjectResultBlock)completionBlock { 72 | 73 | BAAClient *client = [BAAClient sharedClient]; 74 | id c = [self class]; 75 | id resultObject = [[c alloc] init]; 76 | [resultObject setValue:objectID 77 | forKey:@"objectId"]; 78 | [client loadObject:resultObject 79 | completion:completionBlock]; 80 | 81 | } 82 | 83 | - (void) saveObjectWithCompletion:(BAAObjectResultBlock)completionBlock { 84 | 85 | BAAClient *client = [BAAClient sharedClient]; 86 | 87 | if (self.objectId == nil) { 88 | 89 | [client createObject:self 90 | completion:completionBlock]; 91 | 92 | } else { 93 | 94 | [client updateObject:self 95 | completion:completionBlock]; 96 | 97 | } 98 | 99 | } 100 | 101 | - (void) deleteObjectWithCompletion:(BAABooleanResultBlock)completionBlock; { 102 | 103 | BAAClient *client = [BAAClient sharedClient]; 104 | 105 | [client deleteObject:self 106 | completion:completionBlock]; 107 | 108 | } 109 | 110 | - (void) saveObjectWithACL:(NSDictionary *)acl completion:(BAAObjectResultBlock)completionBlock { 111 | 112 | NSAssert(acl != nil, @"ACL should not be nil, otherwise you will delete previously set ACLs."); 113 | NSAssert(acl.allKeys.count > 0, @"ACL should not be empty, otherwise you will delete previously set ACLs."); 114 | _acl = acl; 115 | [self saveObjectWithCompletion:completionBlock]; 116 | 117 | } 118 | 119 | #pragma mark - ACL 120 | 121 | - (void) grantAccessToRole:(NSString *)roleName ofType:(NSString *)accessType completion:(BAAObjectResultBlock)completionBlock { 122 | 123 | [self.client grantAccess:self 124 | toRole:roleName 125 | accessType:accessType 126 | completion:completionBlock]; 127 | 128 | } 129 | 130 | - (void) grantAccessToUser:(NSString *)username ofType:(NSString *)accessType completion:(BAAObjectResultBlock)completionBlock { 131 | 132 | [self.client grantAccess:self 133 | toUser:username 134 | accessType:accessType 135 | completion:completionBlock]; 136 | 137 | } 138 | 139 | - (void) revokeAccessToRole:(NSString *)roleName ofType:(NSString *)accessType completion:(BAAObjectResultBlock)completionBlock { 140 | 141 | [self.client revokeAccess:self 142 | toRole:roleName 143 | accessType:accessType 144 | completion:completionBlock]; 145 | 146 | } 147 | 148 | - (void) revokeAccessToUser:(NSString *)username ofType:(NSString *)accessType completion:(BAAObjectResultBlock)completionBlock { 149 | 150 | [self.client revokeAccess:self 151 | toUser:username 152 | accessType:accessType 153 | completion:completionBlock]; 154 | 155 | } 156 | 157 | 158 | - (NSString *) collectionName { 159 | 160 | return @"OVERWRITE THIS METHOD"; 161 | 162 | } 163 | 164 | - (NSArray *)exclude { 165 | return @[@"superclass", @"description", @"debugDescription"]; 166 | } 167 | 168 | #pragma mark - Counter methods 169 | 170 | + (void) fetchCountForObjectsWithCompletion:(BAAIntegerResultBlock)completionBlock { 171 | 172 | BAAClient *client = [BAAClient sharedClient]; 173 | [client fetchCountForObjects:[[self alloc] init] 174 | completion:completionBlock]; 175 | 176 | } 177 | 178 | #pragma mark - Helper methods 179 | 180 | - (NSDictionary*) objectAsDictionary { 181 | 182 | NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:0]; 183 | 184 | unsigned int outCount, i; 185 | 186 | objc_property_t *properties = class_copyPropertyList([self class], &outCount); 187 | 188 | for(i = 0; i < outCount; i++) { 189 | 190 | objc_property_t property = properties[i]; 191 | const char *propName = property_getName(property); 192 | 193 | NSString *propertyName = [NSString stringWithUTF8String:propName]; 194 | 195 | if (![self.exclude containsObject:propertyName]) { 196 | id value = [self valueForKey:propertyName]; 197 | 198 | if ([value isKindOfClass:[NSArray class]]) { 199 | 200 | NSArray *array = (NSArray *)value; 201 | NSMutableArray *tmp = [NSMutableArray array]; 202 | for (id object in array) { 203 | 204 | if ([object respondsToSelector:@selector(objectAsDictionary)]) { 205 | 206 | [tmp addObject:[object objectAsDictionary]]; 207 | 208 | } else { 209 | 210 | [tmp addObject:object]; 211 | 212 | } 213 | 214 | } 215 | 216 | [dict setValue:tmp forKey:propertyName]; 217 | 218 | } 219 | 220 | else if ([value respondsToSelector:@selector(objectAsDictionary)]) { 221 | 222 | [dict setValue:[value objectAsDictionary] 223 | forKey:propertyName]; 224 | 225 | } 226 | 227 | else if (value && (id)value != [NSNull null]) { 228 | 229 | [dict setValue:value forKey:propertyName]; 230 | 231 | } 232 | } 233 | 234 | } 235 | 236 | free(properties); 237 | 238 | if (self.acl) { 239 | [dict addEntriesFromDictionary:self.acl]; 240 | } 241 | 242 | return dict; 243 | 244 | } 245 | 246 | - (NSString *)jsonString { 247 | 248 | NSError *error = nil; 249 | NSData *jsonData = [NSJSONSerialization dataWithJSONObject:[self objectAsDictionary] 250 | options:NSJSONWritingPrettyPrinted 251 | error:&error]; 252 | 253 | NSString *res = [[NSString alloc] initWithData:jsonData 254 | encoding:NSUTF8StringEncoding]; 255 | 256 | return res; 257 | 258 | } 259 | 260 | + (NSString *) assetsEndPoint { 261 | 262 | NSString *s = [BaasBox baseURL]; 263 | return [NSString stringWithFormat:@"%@%@", s, @"/asset/"]; 264 | 265 | } 266 | 267 | -(NSString *)description { 268 | 269 | return [NSString stringWithFormat:@"<%@> - %@", NSStringFromClass([self class]), self.objectId]; 270 | 271 | } 272 | 273 | #pragma mark - Experimental 274 | 275 | // Random selection should be done on the server side. This is a patch. 276 | // I tested it but might not always work. 277 | 278 | + (void) getRandomObjectsWithParams:(NSDictionary *)parameters bound:(NSInteger)bound completion:(BAAArrayResultBlock)completionBlock { 279 | 280 | if (completionBlock) { 281 | 282 | [[self class] getObjectsWithParams:parameters completion:^(NSArray *objects, NSError *error) { 283 | 284 | if (error == nil) { 285 | 286 | if (bound > objects.count) { 287 | 288 | completionBlock(@[], nil); 289 | 290 | } else { 291 | 292 | NSMutableSet *randomDistinctObjects = [NSMutableSet setWithCapacity:bound]; 293 | 294 | do { 295 | 296 | NSInteger randomIndex = arc4random_uniform((u_int32_t)objects.count); 297 | [randomDistinctObjects addObject:objects[randomIndex]]; 298 | 299 | } while (randomDistinctObjects.count < bound); 300 | 301 | NSArray *result = [randomDistinctObjects allObjects]; 302 | 303 | completionBlock(result, nil); 304 | 305 | } 306 | 307 | } else { 308 | 309 | completionBlock(nil, error); 310 | 311 | } 312 | }]; 313 | } 314 | } 315 | 316 | @end 317 | -------------------------------------------------------------------------------- /BaasBox-iOS-SDK/BAAUser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014. BaasBox 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and limitations under the License. 14 | */ 15 | 16 | #import 17 | #import "BAAGlobals.h" 18 | #import "BAAClient.h" 19 | 20 | @interface BAAUser : NSObject 21 | 22 | @property (nonatomic, copy) NSString *authenticationToken; 23 | @property (nonatomic, copy) NSString *pushNotificationToken; 24 | @property (nonatomic, assign) BOOL pushEnabled; 25 | @property (nonatomic, copy) NSDictionary *roles; 26 | @property (nonatomic, copy) NSString *status; 27 | @property (nonatomic, strong) NSMutableDictionary *visibleByTheUser; 28 | @property (nonatomic, strong) NSMutableDictionary *visibleByFriends; 29 | @property (nonatomic, strong) NSMutableDictionary *visibleByRegisteredUsers; 30 | @property (nonatomic, strong) NSMutableDictionary *visibleByAnonymousUsers; 31 | 32 | - (instancetype) initWithDictionary:(NSDictionary *)dict; 33 | - (NSString *) jsonString; 34 | - (NSString *) username; 35 | 36 | // login/logout 37 | + (void) loginWithUsername:(NSString *)username password:(NSString *)password completion:(BAABooleanResultBlock)completionHandler; 38 | + (void) logoutWithCompletion:(BAABooleanResultBlock)completionBlock; 39 | 40 | // load 41 | + (void) loadCurrentUserWithCompletion:(BAAObjectResultBlock)completionBlock; 42 | + (void) loadUsersWithParameters:(NSDictionary *)parameters completion:(BAAArrayResultBlock)completionBlock; 43 | + (void) loadUserDetails:(NSString *)username completion:(BAAObjectResultBlock)completionBlock; 44 | + (void) loadRandomUserWithCompletion:(BAAArrayResultBlock)completionBlock; 45 | 46 | // Social 47 | + (void) loginWithFacebookToken:(NSString *)token completion:(BAABooleanResultBlock)completionBlock; 48 | - (void) linkToFacebookWithToken:(NSString *)token completion:(BAABooleanResultBlock)completionBlock; 49 | - (void) unlinkFromFacebookWithCompletion:(BAABooleanResultBlock)completionBlock; 50 | + (void) loginWithGoogleToken:(NSString *)token completion:(BAABooleanResultBlock)completionBlock; 51 | - (void) linkToGoogleWithToken:(NSString *)token completion:(BAABooleanResultBlock)completionBlock; 52 | - (void) unlinkFromGoogleWithCompletion:(BAABooleanResultBlock)completionBlock; 53 | - (void) fetchLinkedSocialNetworksWithCompletion:(BAAArrayResultBlock)completionBlock; 54 | 55 | // update 56 | - (void) updateWithCompletion:(BAAObjectResultBlock)completionBlock; 57 | 58 | // Follow/unfollow 59 | - (void) loadFollowingWithCompletion:(BAAArrayResultBlock)completionBlock; 60 | - (void) loadFollowersWithCompletion:(BAAArrayResultBlock)completionBlock; 61 | + (void) followUser:(BAAUser *)user completion:(BAAObjectResultBlock)completionBlock; 62 | + (void) unfollowUser:(BAAUser *)user completion:(BAABooleanResultBlock)completionBlock; 63 | 64 | // Password 65 | - (void) changeOldPassword:(NSString *)oldPassword toNewPassword:(NSString *)newPassword completionBlock:(BAABooleanResultBlock)completionBlock; 66 | - (void) resetPasswordWithCompletion:(BAABooleanResultBlock)completionBlock; 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /BaasBox-iOS-SDK/BAAUser.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014. BaasBox 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and limitations under the License. 14 | */ 15 | 16 | 17 | //http://stablekernel.com/blog/speeding-up-nscoding-with-macros/ 18 | #define OBJC_STRINGIFY(x) @#x 19 | #define encodeObject(x) [aCoder encodeObject:x forKey:OBJC_STRINGIFY(x)] 20 | #define decodeObject(x) x = [aDecoder decodeObjectForKey:OBJC_STRINGIFY(x)] 21 | #define encodeBool(x) [aCoder encodeBool:x forKey:OBJC_STRINGIFY(x)] 22 | #define decodeBool(x) x = [aDecoder decodeBoolForKey:OBJC_STRINGIFY(x)] 23 | #define encodeInteger(x) [aCoder encodeInteger:x forKey:OBJC_STRINGIFY(x)] 24 | #define decodeInteger(x) x = [aDecoder decodeIntegerForKey:OBJC_STRINGIFY(x)] 25 | 26 | #import "BAAUser.h" 27 | #import 28 | 29 | @interface BAAUser () { 30 | 31 | } 32 | 33 | @property (nonatomic, copy) NSMutableDictionary *user; 34 | 35 | @end 36 | 37 | @implementation BAAUser 38 | 39 | 40 | - (instancetype) initWithDictionary:(NSDictionary *)dict { 41 | 42 | self = [super init]; 43 | 44 | if (self) { 45 | 46 | _user = dict[@"user"]; 47 | _roles = dict[@"user"][@"roles"]; 48 | _status = dict[@"user"][@"status"]; 49 | _visibleByAnonymousUsers = [NSMutableDictionary dictionaryWithDictionary:dict[@"visibleByAnonymousUsers"]]; 50 | _visibleByRegisteredUsers = [NSMutableDictionary dictionaryWithDictionary:dict[@"visibleByRegisteredUsers"]]; 51 | 52 | if (dict[@"visibleByFriends"] == [NSNull null]) { 53 | 54 | _visibleByFriends = [NSMutableDictionary dictionary]; 55 | 56 | } else { 57 | 58 | _visibleByFriends = [NSMutableDictionary dictionaryWithDictionary:dict[@"visibleByFriends"]]; 59 | 60 | } 61 | 62 | if (dict[@"visibleByTheUser"] == [NSNull null]) { 63 | 64 | _visibleByTheUser = [NSMutableDictionary dictionary]; 65 | 66 | } else { 67 | 68 | _visibleByTheUser = [NSMutableDictionary dictionaryWithDictionary:dict[@"visibleByTheUser"]]; 69 | 70 | } 71 | 72 | } 73 | 74 | return self; 75 | 76 | } 77 | 78 | #pragma mark - Login 79 | 80 | + (void) loginWithUsername:(NSString *)username password:(NSString *)password completion:(BAABooleanResultBlock)completionHandler { 81 | 82 | BAAClient *client = [BAAClient sharedClient]; 83 | [client authenticateUser:username password:password completion:^(BOOL success, NSError *error) { 84 | 85 | if (completionHandler) { 86 | completionHandler(success, error); 87 | } 88 | 89 | }]; 90 | 91 | } 92 | 93 | + (void) logoutWithCompletion:(BAABooleanResultBlock)completionBlock { 94 | 95 | BAAClient *client = [BAAClient sharedClient]; 96 | [client logoutWithCompletion:^(BOOL success, NSError *error) { 97 | 98 | if (completionBlock) { 99 | completionBlock(success, error); 100 | } 101 | 102 | }]; 103 | 104 | } 105 | 106 | #pragma mark - Load 107 | 108 | + (void) loadCurrentUserWithCompletion:(BAAObjectResultBlock)completionBlock { 109 | 110 | BAAClient *client = [BAAClient sharedClient]; 111 | [client loadCurrentUserWithCompletion:^(BAAUser *user, NSError *error) { 112 | 113 | if (completionBlock){ 114 | completionBlock(user, error); 115 | } 116 | 117 | }]; 118 | 119 | } 120 | 121 | + (void) loadUsersWithParameters:(NSDictionary *)parameters completion:(BAAArrayResultBlock)completionBlock { 122 | 123 | BAAClient *client = [BAAClient sharedClient]; 124 | [client loadUsersWithParameters:parameters 125 | completion:^(NSArray *users, NSError *error) { 126 | 127 | if (completionBlock) { 128 | 129 | if (error == nil) { 130 | 131 | completionBlock(users, nil); 132 | 133 | } else { 134 | 135 | completionBlock(nil, error); 136 | 137 | } 138 | } 139 | 140 | }]; 141 | 142 | } 143 | 144 | + (void) loadRandomUserWithCompletion:(BAAArrayResultBlock)completionBlock { 145 | 146 | if (completionBlock) { 147 | 148 | [self loadUsersWithParameters:@{} completion:^(NSArray *users, NSError *error) { 149 | 150 | if (error == nil) { 151 | 152 | if (users.count <= 1) { 153 | 154 | // This is the edge case where this user is the only user. 155 | completionBlock(@[], nil); 156 | 157 | } else { 158 | 159 | BAAUser *currentUser = [[BAAClient sharedClient] currentUser]; 160 | BAAUser *randomUser; 161 | 162 | do { 163 | 164 | NSInteger randomIndex = arc4random_uniform((u_int32_t)users.count); 165 | randomUser = users[randomIndex]; 166 | 167 | } while ([randomUser.username isEqualToString:currentUser.username]); // Ensures that the random user is not the current user. 168 | 169 | completionBlock([NSArray arrayWithObject:randomUser], nil); 170 | 171 | } 172 | 173 | } else { 174 | completionBlock(nil, error); 175 | } 176 | }]; 177 | } 178 | } 179 | 180 | + (void) loadUserDetails:(NSString *)username completion:(BAAObjectResultBlock)completionBlock { 181 | 182 | BAAClient *client = [BAAClient sharedClient]; 183 | 184 | [client loadUsersDetails:username 185 | completion:^(BAAUser *user, NSError *error) { 186 | 187 | if (completionBlock) 188 | completionBlock(user, error); 189 | 190 | }]; 191 | 192 | } 193 | 194 | - (void) loadFollowingWithCompletion:(BAAArrayResultBlock)completionBlock { 195 | 196 | BAAClient *client = [BAAClient sharedClient]; 197 | [client loadFollowingForUser:self 198 | completion:^(NSArray *users, NSError *error) { 199 | 200 | if (completionBlock) 201 | completionBlock(users, error); 202 | 203 | }]; 204 | 205 | } 206 | 207 | - (void) loadFollowersWithCompletion:(BAAArrayResultBlock)completionBlock { 208 | 209 | BAAClient *client = [BAAClient sharedClient]; 210 | [client loadFollowersOfUser:self 211 | completion:^(NSArray *users, NSError *error) { 212 | 213 | if (completionBlock) { 214 | completionBlock(users, error); 215 | } 216 | 217 | }]; 218 | 219 | } 220 | 221 | #pragma mark - Social 222 | 223 | + (void) loginWithFacebookToken:(NSString *)token completion:(BAABooleanResultBlock)completionBlock { 224 | 225 | BAAClient *client = [BAAClient sharedClient]; 226 | [client postPath:@"/social/facebook" 227 | parameters:@{@"oauth_token":token, @"oauth_secret":token} 228 | success:^(id responseObject) { 229 | 230 | BAAUser *user = [[BAAUser alloc] initWithDictionary:responseObject[@"data"]]; 231 | user.authenticationToken = responseObject[@"data"][@"X-BB-SESSION"]; 232 | client.currentUser = user; 233 | [client saveUserToDisk:user]; 234 | if (completionBlock) { 235 | completionBlock(YES, nil); 236 | } 237 | 238 | } failure:^(NSError *error) { 239 | 240 | if (completionBlock) { 241 | completionBlock(NO, error); 242 | } 243 | 244 | }]; 245 | 246 | } 247 | 248 | - (void) linkToFacebookWithToken:(NSString *)token completion:(BAABooleanResultBlock)completionBlock { 249 | 250 | BAAClient *client = [BAAClient sharedClient]; 251 | [client putPath:@"/social/facebook" 252 | parameters:@{@"oauth_token":token, @"oauth_secret":token} 253 | success:^(id responseObject) { 254 | if (completionBlock) { 255 | completionBlock(YES, nil); 256 | } 257 | } failure:^(NSError *error) { 258 | if (completionBlock) { 259 | completionBlock(NO, error); 260 | } 261 | }]; 262 | 263 | } 264 | 265 | - (void) unlinkFromFacebookWithCompletion:(BAABooleanResultBlock)completionBlock { 266 | 267 | BAAClient *client = [BAAClient sharedClient]; 268 | [client deletePath:@"/social/facebook" 269 | parameters:nil 270 | success:^(id responseObject) { 271 | if (completionBlock) { 272 | completionBlock(YES, nil); 273 | } 274 | } failure:^(NSError *error) { 275 | if (completionBlock) { 276 | completionBlock(NO, error); 277 | } 278 | }]; 279 | 280 | } 281 | 282 | + (void) loginWithGoogleToken:(NSString *)token completion:(BAABooleanResultBlock)completionBlock { 283 | 284 | BAAClient *client = [BAAClient sharedClient]; 285 | [client postPath:@"/social/google" 286 | parameters:@{@"oauth_token":token, @"oauth_secret":token} 287 | success:^(id responseObject) { 288 | 289 | BAAUser *user = [[BAAUser alloc] initWithDictionary:responseObject[@"data"]]; 290 | user.authenticationToken = responseObject[@"data"][@"X-BB-SESSION"]; 291 | client.currentUser = user; 292 | [client saveUserToDisk:user]; 293 | if (completionBlock) { 294 | completionBlock(YES, nil); 295 | } 296 | 297 | } failure:^(NSError *error) { 298 | 299 | if (completionBlock) { 300 | completionBlock(NO, error); 301 | } 302 | 303 | }]; 304 | 305 | } 306 | 307 | - (void) linkToGoogleWithToken:(NSString *)token completion:(BAABooleanResultBlock)completionBlock { 308 | 309 | BAAClient *client = [BAAClient sharedClient]; 310 | [client putPath:@"/social/google" 311 | parameters:@{@"oauth_token":token, @"oauth_secret":token} 312 | success:^(id responseObject) { 313 | if (completionBlock) { 314 | completionBlock(YES, nil); 315 | } 316 | } failure:^(NSError *error) { 317 | if (completionBlock) { 318 | completionBlock(NO, error); 319 | } 320 | }]; 321 | 322 | } 323 | 324 | - (void) unlinkFromGoogleWithCompletion:(BAABooleanResultBlock)completionBlock { 325 | 326 | BAAClient *client = [BAAClient sharedClient]; 327 | [client deletePath:@"/social/google" 328 | parameters:nil 329 | success:^(id responseObject) { 330 | if (completionBlock) { 331 | completionBlock(YES, nil); 332 | } 333 | } failure:^(NSError *error) { 334 | if (completionBlock) { 335 | completionBlock(NO, error); 336 | } 337 | }]; 338 | 339 | } 340 | 341 | - (void) fetchLinkedSocialNetworksWithCompletion:(BAAArrayResultBlock)completionBlock { 342 | 343 | BAAClient *client = [BAAClient sharedClient]; 344 | [client getPath:@"/social" 345 | parameters:nil 346 | success:^(id responseObject) { 347 | if (completionBlock) { 348 | NSArray *res = responseObject[@"data"]; 349 | completionBlock(res, nil); 350 | } 351 | } failure:^(NSError *error) { 352 | if(completionBlock) { 353 | completionBlock(nil, error); 354 | } 355 | }]; 356 | 357 | } 358 | 359 | #pragma mark - Update 360 | 361 | - (void) updateWithCompletion:(BAAObjectResultBlock)completionBlock { 362 | 363 | BAAClient *client = [BAAClient sharedClient]; 364 | [client updateUserWithCompletion:completionBlock]; 365 | 366 | } 367 | 368 | #pragma mark - Follow/Unfollow 369 | 370 | + (void) followUser:(BAAUser *)user completion:(BAAObjectResultBlock)completionBlock { 371 | 372 | BAAClient *client = [BAAClient sharedClient]; 373 | [client followUser:user 374 | completion:^(BAAUser *user, NSError *error) { 375 | 376 | if (completionBlock) 377 | completionBlock(user, error); 378 | 379 | }]; 380 | 381 | } 382 | 383 | + (void) unfollowUser:(BAAUser *)user completion:(BAABooleanResultBlock)completionBlock { 384 | 385 | BAAClient *client = [BAAClient sharedClient]; 386 | [client unfollowUser:user 387 | completion:^(BOOL success, NSError *error) { 388 | 389 | if (completionBlock) 390 | completionBlock(success, error); 391 | 392 | }]; 393 | 394 | } 395 | 396 | - (void) changeOldPassword:(NSString *)oldPassword toNewPassword:(NSString *)newPassword completionBlock:(BAABooleanResultBlock)completionBlock { 397 | 398 | BAAClient *client = [BAAClient sharedClient]; 399 | [client changeOldPassword:oldPassword 400 | toNewPassword:newPassword 401 | completion:completionBlock]; 402 | 403 | } 404 | 405 | - (void) resetPasswordWithCompletion:(BAABooleanResultBlock)completionBlock { 406 | 407 | BAAClient *client = [BAAClient sharedClient]; 408 | [client resetPasswordForUsername:self.username 409 | withCompletion:completionBlock]; 410 | 411 | } 412 | 413 | 414 | #pragma mark - Helpers 415 | 416 | - (NSDictionary*) objectAsDictionary { 417 | 418 | NSArray *exclude = @[@"authenticationToken", @"pushNotificationToken", @"pushEnabled", @"roles"]; 419 | NSMutableDictionary *result = [NSMutableDictionary dictionary]; 420 | unsigned int propertiesCount; 421 | objc_property_t *propertyList = class_copyPropertyList([self class], &propertiesCount); 422 | 423 | for (int i = 0 ; i < propertiesCount; i++) { 424 | objc_property_t property = propertyList[i]; 425 | const char *propertyChar = property_getName(property); 426 | NSString *propertyName = [NSString stringWithCString:propertyChar 427 | encoding:NSASCIIStringEncoding]; 428 | 429 | if (![exclude containsObject:propertyName]) { 430 | 431 | id value = [self valueForKey:propertyName]; 432 | 433 | if (value) { 434 | 435 | [result setObject:value forKey:propertyName]; 436 | 437 | } 438 | 439 | } 440 | 441 | } 442 | 443 | free(propertyList); 444 | return [NSDictionary dictionaryWithDictionary:result]; 445 | 446 | } 447 | 448 | - (NSString *) jsonString { 449 | 450 | NSError *error = nil; 451 | NSData *jsonData = [NSJSONSerialization dataWithJSONObject:[self objectAsDictionary] 452 | options:NSJSONWritingPrettyPrinted 453 | error:&error]; 454 | NSString *res = [[NSString alloc] initWithData:jsonData 455 | encoding:NSUTF8StringEncoding]; 456 | return res; 457 | 458 | } 459 | 460 | - (NSMutableDictionary *) visibleByAnonymousUsers { 461 | 462 | if (_visibleByAnonymousUsers == nil) { 463 | _visibleByAnonymousUsers = [NSMutableDictionary dictionary]; 464 | } 465 | 466 | return _visibleByAnonymousUsers; 467 | 468 | } 469 | 470 | - (NSMutableDictionary *) visibleByTheUser { 471 | 472 | if (_visibleByTheUser == nil) { 473 | _visibleByTheUser = [NSMutableDictionary dictionary]; 474 | } 475 | 476 | return _visibleByTheUser; 477 | 478 | } 479 | 480 | - (NSMutableDictionary *) visibleByFriends { 481 | 482 | if (_visibleByFriends == nil) { 483 | _visibleByFriends = [NSMutableDictionary dictionary]; 484 | } 485 | 486 | return _visibleByFriends; 487 | 488 | } 489 | 490 | - (NSMutableDictionary *) visibleByRegisteredUsers { 491 | 492 | if (_visibleByRegisteredUsers == nil) { 493 | _visibleByRegisteredUsers = [NSMutableDictionary dictionary]; 494 | } 495 | 496 | return _visibleByRegisteredUsers; 497 | 498 | } 499 | 500 | - (NSString *) username { 501 | 502 | if ([self.visibleByRegisteredUsers[@"_social"] count] > 0) { 503 | return self.visibleByTheUser[@"name"]; 504 | } else { 505 | return self.user[@"name"]; 506 | } 507 | 508 | } 509 | 510 | - (NSString *)description { 511 | 512 | return [[self objectAsDictionary] description]; 513 | 514 | } 515 | 516 | #pragma mark - NSCoding 517 | 518 | - (id)initWithCoder:(NSCoder *)aDecoder { 519 | 520 | self = [super init]; 521 | 522 | if(self) { 523 | 524 | decodeObject(_user); 525 | decodeObject(_authenticationToken); 526 | decodeObject(_pushNotificationToken); 527 | decodeBool(_pushEnabled); 528 | decodeObject(_visibleByAnonymousUsers); 529 | decodeObject(_visibleByRegisteredUsers); 530 | decodeObject(_visibleByFriends); 531 | decodeObject(_visibleByTheUser); 532 | 533 | } 534 | 535 | return self; 536 | 537 | } 538 | 539 | - (void)encodeWithCoder:(NSCoder *)aCoder { 540 | 541 | encodeObject(_user); 542 | encodeObject(_authenticationToken); 543 | encodeObject(_pushNotificationToken); 544 | encodeBool(_pushEnabled); 545 | encodeObject(_visibleByAnonymousUsers); 546 | encodeObject(_visibleByRegisteredUsers); 547 | encodeObject(_visibleByFriends); 548 | encodeObject(_visibleByTheUser); 549 | 550 | } 551 | 552 | @end 553 | -------------------------------------------------------------------------------- /BaasBox-iOS-SDK/BaasBox.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014. BaasBox 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and limitations under the License. 14 | */ 15 | 16 | #import 17 | #if TARGET_OS_IPHONE 18 | #import 19 | #else 20 | #import 21 | #endif 22 | 23 | #define VERSION @"0.9.4" 24 | #define BASE_URL_KEY @"baseURLKey" 25 | #define APP_CODE_KEY @"appCodeKey" 26 | 27 | @interface BaasBox : NSObject 28 | 29 | + (void) setBaseURL:(NSString *)URL appCode:(NSString *)code; 30 | + (NSString *) baseURL; 31 | + (NSString *) appCode; 32 | + (NSString *) errorDomain; 33 | + (NSInteger) errorCode; 34 | + (NSError *)authenticationErrorForResponse:(NSDictionary *)response; 35 | + (NSDateFormatter *)dateFormatter; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /BaasBox-iOS-SDK/BaasBox.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014. BaasBox 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and limitations under the License. 14 | */ 15 | 16 | #import "BaasBox.h" 17 | 18 | @implementation BaasBox 19 | 20 | + (void) setBaseURL:(NSString *)URL appCode:(NSString *)code { 21 | 22 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 23 | [userDefaults setObject:URL forKey:BASE_URL_KEY]; 24 | [userDefaults setObject:code forKey:APP_CODE_KEY]; 25 | [userDefaults synchronize]; 26 | 27 | } 28 | 29 | + (NSString *) baseURL { 30 | 31 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 32 | return (NSString *) [userDefaults objectForKey:BASE_URL_KEY]; 33 | 34 | } 35 | 36 | + (NSString *) appCode { 37 | 38 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; 39 | return (NSString *) [userDefaults objectForKey:APP_CODE_KEY]; 40 | 41 | } 42 | 43 | + (NSString *) errorDomain { 44 | return @"com.baasbox.error"; 45 | } 46 | 47 | + (NSInteger) errorCode { 48 | return -13579; 49 | } 50 | 51 | + (NSError *)authenticationErrorForResponse:(NSDictionary *)response { 52 | 53 | if (response == nil) { 54 | NSDictionary *errorDetail = @{NSLocalizedDescriptionKey:@"Server returned an empty response.", 55 | @"BaasBox API Version": @[response[@"API_version"]], 56 | @"iOS SDK Version" : VERSION}; 57 | return [NSError errorWithDomain:[BaasBox errorDomain] 58 | code:-22222 59 | userInfo:errorDetail]; 60 | } 61 | 62 | NSDictionary *errorDetail = @{NSLocalizedDescriptionKey:response[@"message"], 63 | @"BaasBox_API_version": @[response[@"API_version"]], 64 | @"iOS SDK Version" : VERSION}; 65 | NSError *error = [NSError errorWithDomain:[BaasBox errorDomain] 66 | code:-22222 67 | userInfo:errorDetail]; 68 | return error; 69 | 70 | } 71 | 72 | + (NSDateFormatter *)dateFormatter { 73 | 74 | static NSDateFormatter *_dateFormatter = nil; 75 | static dispatch_once_t onceToken; 76 | dispatch_once(&onceToken, ^{ 77 | _dateFormatter = [[NSDateFormatter alloc] init]; 78 | [_dateFormatter setDateFormat:@"yyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"]; 79 | }); 80 | 81 | return _dateFormatter; 82 | 83 | } 84 | 85 | @end 86 | -------------------------------------------------------------------------------- /BaasBoxSDK.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | spec.name = 'BaasBoxSDK' 3 | spec.version = '0.9.0' 4 | spec.summary = 'iOS SDK for the open source back end BaasBox. See http://www.baasbox.com' 5 | spec.homepage = 'https://github.com/baasbox/iOS-SDK' 6 | spec.author = { 'Cesare Rocchi' => 'c.rocchi@baasbox.com' } 7 | spec.source = { :git => 'https://github.com/baasbox/iOS-SDK.git', :tag => "v0.9.0" } 8 | spec.platform = :ios 9 | spec.ios.deployment_target = "7.0" 10 | spec.source_files = 'BaasBox-iOS-SDK/*.{h,m}' 11 | spec.requires_arc = true 12 | spec.license = { :type => 'APACHE2', :file => 'LICENSE' } 13 | end -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 13 | owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities 16 | that control, are controlled by, or are under common control with that entity. 17 | For the purposes of this definition, "control" means (i) the power, direct or 18 | indirect, to cause the direction or management of such entity, whether by 19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 20 | outstanding shares, or (iii) beneficial ownership of such entity. 21 | 22 | "You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, including 26 | but not limited to software source code, documentation source, and configuration 27 | files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation or 30 | translation of a Source form, including but not limited to compiled object code, 31 | generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, made 34 | available under the License, as indicated by a copyright notice that is included 35 | in or attached to the work (an example is provided in the Appendix below). 36 | 37 | "Derivative Works" shall mean any work, whether in Source or Object form, that 38 | is based on (or derived from) the Work and for which the editorial revisions, 39 | annotations, elaborations, or other modifications represent, as a whole, an 40 | original work of authorship. For the purposes of this License, Derivative Works 41 | shall not include works that remain separable from, or merely link (or bind by 42 | name) to the interfaces of, the Work and Derivative Works thereof. 43 | 44 | "Contribution" shall mean any work of authorship, including the original version 45 | of the Work and any modifications or additions to that Work or Derivative Works 46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 47 | by the copyright owner or by an individual or Legal Entity authorized to submit 48 | on behalf of the copyright owner. For the purposes of this definition, 49 | "submitted" means any form of electronic, verbal, or written communication sent 50 | to the Licensor or its representatives, including but not limited to 51 | communication on electronic mailing lists, source code control systems, and 52 | issue tracking systems that are managed by, or on behalf of, the Licensor for 53 | the purpose of discussing and improving the Work, but excluding communication 54 | that is conspicuously marked or otherwise designated in writing by the copyright 55 | owner as "Not a Contribution." 56 | 57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 58 | of whom a Contribution has been received by Licensor and subsequently 59 | incorporated within the Work. 60 | 61 | 2. Grant of Copyright License. 62 | 63 | Subject to the terms and conditions of this License, each Contributor hereby 64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 65 | irrevocable copyright license to reproduce, prepare Derivative Works of, 66 | publicly display, publicly perform, sublicense, and distribute the Work and such 67 | Derivative Works in Source or Object form. 68 | 69 | 3. Grant of Patent License. 70 | 71 | Subject to the terms and conditions of this License, each Contributor hereby 72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 73 | irrevocable (except as stated in this section) patent license to make, have 74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 75 | such license applies only to those patent claims licensable by such Contributor 76 | that are necessarily infringed by their Contribution(s) alone or by combination 77 | of their Contribution(s) with the Work to which such Contribution(s) was 78 | submitted. If You institute patent litigation against any entity (including a 79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 80 | Contribution incorporated within the Work constitutes direct or contributory 81 | patent infringement, then any patent licenses granted to You under this License 82 | for that Work shall terminate as of the date such litigation is filed. 83 | 84 | 4. Redistribution. 85 | 86 | You may reproduce and distribute copies of the Work or Derivative Works thereof 87 | in any medium, with or without modifications, and in Source or Object form, 88 | provided that You meet the following conditions: 89 | 90 | You must give any other recipients of the Work or Derivative Works a copy of 91 | this License; and 92 | You must cause any modified files to carry prominent notices stating that You 93 | changed the files; and 94 | You must retain, in the Source form of any Derivative Works that You distribute, 95 | all copyright, patent, trademark, and attribution notices from the Source form 96 | of the Work, excluding those notices that do not pertain to any part of the 97 | Derivative Works; and 98 | If the Work includes a "NOTICE" text file as part of its distribution, then any 99 | Derivative Works that You distribute must include a readable copy of the 100 | attribution notices contained within such NOTICE file, excluding those notices 101 | that do not pertain to any part of the Derivative Works, in at least one of the 102 | following places: within a NOTICE text file distributed as part of the 103 | Derivative Works; within the Source form or documentation, if provided along 104 | with the Derivative Works; or, within a display generated by the Derivative 105 | Works, if and wherever such third-party notices normally appear. The contents of 106 | the NOTICE file are for informational purposes only and do not modify the 107 | License. You may add Your own attribution notices within Derivative Works that 108 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 109 | provided that such additional attribution notices cannot be construed as 110 | modifying the License. 111 | You may add Your own copyright statement to Your modifications and may provide 112 | additional or different license terms and conditions for use, reproduction, or 113 | distribution of Your modifications, or for any such Derivative Works as a whole, 114 | provided Your use, reproduction, and distribution of the Work otherwise complies 115 | with the conditions stated in this License. 116 | 117 | 5. Submission of Contributions. 118 | 119 | Unless You explicitly state otherwise, any Contribution intentionally submitted 120 | for inclusion in the Work by You to the Licensor shall be under the terms and 121 | conditions of this License, without any additional terms or conditions. 122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 123 | any separate license agreement you may have executed with Licensor regarding 124 | such Contributions. 125 | 126 | 6. Trademarks. 127 | 128 | This License does not grant permission to use the trade names, trademarks, 129 | service marks, or product names of the Licensor, except as required for 130 | reasonable and customary use in describing the origin of the Work and 131 | reproducing the content of the NOTICE file. 132 | 133 | 7. Disclaimer of Warranty. 134 | 135 | Unless required by applicable law or agreed to in writing, Licensor provides the 136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 138 | including, without limitation, any warranties or conditions of TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 140 | solely responsible for determining the appropriateness of using or 141 | redistributing the Work and assume any risks associated with Your exercise of 142 | permissions under this License. 143 | 144 | 8. Limitation of Liability. 145 | 146 | In no event and under no legal theory, whether in tort (including negligence), 147 | contract, or otherwise, unless required by applicable law (such as deliberate 148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 149 | liable to You for damages, including any direct, indirect, special, incidental, 150 | or consequential damages of any character arising as a result of this License or 151 | out of the use or inability to use the Work (including but not limited to 152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 153 | any and all other commercial damages or losses), even if such Contributor has 154 | been advised of the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. 157 | 158 | While redistributing the Work or Derivative Works thereof, You may choose to 159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 160 | other liability obligations and/or rights consistent with this License. However, 161 | in accepting such obligations, You may act only on Your own behalf and on Your 162 | sole responsibility, not on behalf of any other Contributor, and only if You 163 | agree to indemnify, defend, and hold each Contributor harmless for any liability 164 | incurred by, or claims asserted against, such Contributor by reason of your 165 | accepting any such warranty or additional liability. 166 | 167 | END OF TERMS AND CONDITIONS 168 | 169 | APPENDIX: How to apply the Apache License to your work 170 | 171 | To apply the Apache License to your work, attach the following boilerplate 172 | notice, with the fields enclosed by brackets "[]" replaced with your own 173 | identifying information. (Don't include the brackets!) The text should be 174 | enclosed in the appropriate comment syntax for the file format. We also 175 | recommend that a file or class name and description of purpose be included on 176 | the same "printed page" as the copyright notice for easier identification within 177 | third-party archives. 178 | 179 | Copyright [yyyy] [name of copyright owner] 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. 192 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | BaasBox iOS SDK 2 | ======= 3 | 4 | This is the official iOS SDK for [BaasBox](http://www.baasbox.com) 5 | 6 | #Installation 7 | 8 | ## CocoaPods 9 | 10 | Add the following to your Podfile 11 | 12 | ``pod 'BaasBoxSDK', '~> 0.9.0'`` 13 | 14 | ## Good old way 15 | 16 | Download this repo and drag the `BaasBox-iOS-SDK` folder on your Xcode project. 17 | 18 | #Importing 19 | 20 | Add `#import "BAAClient.h"` to the .pch file of your project and you are good to go. 21 | 22 | For Swift projects import all the .h and .m files. Xcode will ask you to create a bridging header. Say yes. 23 | Then add the following to the bridging header file `#import "BAAClient.h"`. Tested with Xcode6 beta6. 24 | 25 | #Documentation 26 | Read documentation here: [http://www.baasbox.com/documentation](http://www.baasbox.com/documentation) 27 | 28 | #License 29 | 30 | This SDK is released under the Apache 2 license. See the LICENSE file for more details. 31 | 32 | We are gonna write a tutorial soon. Check out [our blog](http://www.baasbox.com/blog/) 33 | --------------------------------------------------------------------------------