Files
watrbx-game-engine/iOS/RobloxUI/Source/Data/RobloxData.m
T
2025-09-18 17:55:52 -04:00

2970 lines
118 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//
// RobloxData.m
// NativeShell-iOS
//
// Created by alichtin on 4/25/14.
// Copyright (c) 2014 Roblox. All rights reserved.
//
#import "RobloxData.h"
#import "ABTestManager.h"
#import "RBXFunctions.h"
#import "RobloxInfo.h"
#import "NSDictionary+Parsing.h"
#import "SessionReporter.h"
#import "RobloxXSRFRequest.h"
#import "AFHTTPRequestOperation.h"
static dispatch_queue_t _completionQueue;
// GameData
@implementation RBXGameData
+ (RBXGameData*) parseGameFromJSON:(NSDictionary*)jsonGame
{
RBXGameData* game = [[RBXGameData alloc] init];
game.players = [jsonGame stringForKey:@"PlayerCount"];
game.title = [jsonGame stringForKey:@"Name"];
game.creatorName = [jsonGame stringForKey:@"CreatorName"];
game.creatorID = [jsonGame numberForKey:@"CreatorID"];
game.placeID = [jsonGame stringForKey:@"PlaceID"];
game.visited = [jsonGame unsignedValueForKey:@"Plays"];
game.userFavorited = NO;
game.userVote = RBXUserVoteNoVote;
game.userOwns = [jsonGame boolValueForKey:@"IsOwned"];
game.productID = [jsonGame unsignedValueForKey:@"ProductID"];
game.price = [jsonGame unsignedValueForKey:@"Price"];
game.thumbnailURL = [jsonGame stringForKey:@"ThumbnailUrl"];
game.thumbnailIsFinal = [jsonGame boolValueForKey:@"ThumbnailIsFinal"];
game.universeID = [jsonGame numberForKey:@"UniverseID" withDefault:nil];
game.upVotes = [jsonGame unsignedValueForKey:@"TotalUpVotes"];
game.downVotes = [jsonGame unsignedValueForKey:@"TotalDownVotes"];
return game;
}
@end
// GameAttribute
@implementation RBXGameAttribute
@end
// GameSort
@implementation RBXGameSort
+(RBXGameSort*) GameSortWithJSON:(NSDictionary*)json
{
RBXGameSort* sort = [[RBXGameSort alloc] init];
sort.sortID = [json numberForKey:@"Id"];
sort.title = [json stringForKey:@"Name"];
return sort;
}
+(RBXGameSort*) RecentlyPlayedGamesSort
{
RBXGameSort* sort = [[RBXGameSort alloc] init];
sort.sortID = [NSNumber numberWithInt:RBXGameSortTypeMyRecent]; // old 6
sort.title = NSLocalizedString(@"RecentlyWord", nil);
return sort;
}
+(RBXGameSort*) MyGamesSort
{
RBXGameSort* sort = [[RBXGameSort alloc] init];
sort.sortID = [NSNumber numberWithInt:RBXGameSortTypeMyRecent];
sort.title = NSLocalizedString(@"MyWord", nil);
return sort;
}
+(RBXGameSort*) FavoriteGamesSort
{
RBXGameSort* sort = [[RBXGameSort alloc] init];
sort.sortID = [NSNumber numberWithInt:RBXGameSortTypeMyFavorite];
sort.title = NSLocalizedString(@"FavoritedWord", nil);
return sort;
}
+(RBXGameSort*) DefaultSort
{
RBXGameSort* sort = [[RBXGameSort alloc] init];
sort.sortID = [NSNumber numberWithInt:RBXGameSortTypeDefault];
sort.title = NSLocalizedString(@"DefaultWord", nil);
return sort;
}
- (BOOL)isEqual:(id)object
{
return [super isEqual:object]
&& [((RBXGameSort*)object).sortID isEqualToNumber:_sortID];
}
@end
// GameGenre
@implementation RBXGameGenre
+(RBXGameGenre*) gameGenreWithId:(NSNumber *)genreID name:(NSString *)genreName {
RBXGameGenre *genre = [[RBXGameGenre alloc] init];
genre.genreID = genreID;
genre.title = genreName;
return genre;
}
+(NSArray*) allGenres {
NSMutableArray *genresToUse = nil;
NSInteger minGenres = 5;
// 2015.0902 ajain - See if there are remote genres in the iOS App Settings; if so then
// use the remote genres
NSString *remoteGenreString = [RobloxInfo gameGenres];
if ([remoteGenreString isKindOfClass:[NSString class]] && ![RBXFunctions isEmptyString:remoteGenreString]) {
NSArray *remoteGenres = [remoteGenreString componentsSeparatedByString:@"|"];
genresToUse = [NSMutableArray arrayWithCapacity:remoteGenres.count];
for (NSString *remoteGenre in remoteGenres) {
NSArray *genreParts = [remoteGenre componentsSeparatedByString:@"-"];
NSString *genreName = genreParts.firstObject;
if ([genreName rangeOfString:@"+"].location != NSNotFound) {
NSArray *nameParts = [genreName componentsSeparatedByString:@"+"];
NSMutableString *newGenreName = [NSMutableString string];
for (NSInteger i = 0; i < nameParts.count; i++) {
NSString *namePart = nameParts[i];
[newGenreName appendString:namePart];
if (i < nameParts.count - 1) {
[newGenreName appendString:@" "];
}
}
genreName = newGenreName;
}
NSNumber *genreID = genreParts.lastObject;
RBXGameGenre *newGenre = [RBXGameGenre gameGenreWithId:genreID name:genreName];
[genresToUse addObject:newGenre];
}
// Sort the remote list of genres alphabetically
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"title" ascending:YES];
NSMutableArray *sortedGenres = [[genresToUse sortedArrayUsingDescriptors:@[sort]] mutableCopy];
// Find the Genre-All and put it at index position 0
for (RBXGameGenre *genre in sortedGenres) {
if ([genre.title.lowercaseString isEqualToString:@"All".lowercaseString]) {
// Remove the Genre-All from wherever it is in the array
[sortedGenres removeObject:genre];
// And insert the Genre-All as the first position in the list
[sortedGenres insertObject:genre atIndex:0];
break;
}
}
genresToUse = sortedGenres;
}
// 2015.0902 ajain - Try to do some cursory level of validation of the remote genres
BOOL remoteGenresInvalid = ([RBXFunctions isEmpty:genresToUse] || genresToUse.count < minGenres);
// 2015.0902 ajain - If we can't use the remote genres then we can use the local default genres
if (remoteGenresInvalid) {
genresToUse = [@[
[self gameGenreWithId:@(1) name:@"All"],
[self gameGenreWithId:@(13) name:@"Adventure"],
[self gameGenreWithId:@(19) name:@"Building"],
[self gameGenreWithId:@(15) name:@"Comedy"],
[self gameGenreWithId:@(10) name:@"Fighting"],
[self gameGenreWithId:@(20) name:@"FPS"],
[self gameGenreWithId:@(11) name:@"Horror"],
[self gameGenreWithId:@(8) name:@"Medieval"],
[self gameGenreWithId:@(17) name:@"Military"],
[self gameGenreWithId:@(12) name:@"Naval"],
[self gameGenreWithId:@(21) name:@"RPG"],
[self gameGenreWithId:@(9) name:@"SciFi"],
[self gameGenreWithId:@(14) name:@"Sports"],
[self gameGenreWithId:@(7) name:@"Town and City"],
[self gameGenreWithId:@(16) name:@"Western"]
] mutableCopy];
}
return genresToUse;
}
@end
// LeaderboardEntry
@implementation RBXLeaderboardEntry
+ (RBXLeaderboardEntry*) parseLeaderboardEntry:(NSDictionary*)jsonEntry
{
RBXLeaderboardEntry* entry = [[RBXLeaderboardEntry alloc] init];
NSInteger rank = [jsonEntry intValueForKey:@"Rank" withDefault:-1];
if(rank != -1)
entry.displayRank = [jsonEntry stringForKey:@"DisplayRank"];
else
entry.displayRank = @"";
entry.name = [jsonEntry stringForKey:@"Name"];
entry.rank = rank;
entry.userID = [jsonEntry unsignedValueForKey:@"UserId"];
entry.targetID = [jsonEntry unsignedValueForKey:@"TargetId"];
entry.clanName = [jsonEntry stringForKey:@"ClanName"];
entry.points = [jsonEntry unsignedValueForKey:@"Points"];
entry.displayPoints = [jsonEntry stringForKey:@"DisplayPoints"];
entry.clanEmblemID = [jsonEntry unsignedValueForKey:@"ClanEmblemID"];
entry.userAvatarURL = [jsonEntry stringForKey:@"UserImageUri"];
entry.userAvatarIsFinal = [jsonEntry boolValueForKey:@"UserImageFinal"];
entry.clanAvatarURL = [jsonEntry stringForKey:@"ClanImageUri"];
entry.clanAvatarIsFinal = [jsonEntry boolValueForKey:@"ClanImageFinal"];
return entry;
}
@end
// User profile info
@implementation RBXUserProfileInfo
+(RBXUserProfileInfo*) UserProfileInfoWithJSON:(NSDictionary*)json
{
RBXUserProfileInfo* profile = [[RBXUserProfileInfo alloc] init];
profile.userID = [json numberForKey:@"UserId"];
profile.username = [json stringForKey:@"Username"];
profile.avatarURL = [json stringForKey:@"AvatarUri"];
profile.avatarIsFinal = [json boolValueForKey:@"AvatarFinal"];
profile.BC = [json boolValueForKey:@"BC"];
profile.TBC = [json boolValueForKey:@"TBC"];
profile.OBC = [json boolValueForKey:@"OBC"];
profile.robux = [json unsignedValueForKey:@"Robux" withDefault:-1];
profile.tickets = [json unsignedValueForKey:@"Tickets" withDefault:-1];
profile.friendshipStatus = [json unsignedValueForKey:@"FriendshipStatus"];
profile.isFollowing = [json boolValueForKey:@"IsFollowingDisplayedUser" withDefault:NO];
return profile;
}
@end
@implementation RBXUserAccount
//THIS WILL NEED TO BE UPDATED AT SOME POINT
//{"UserId":68465808,"Name":"iMightBeLying","UserEmail":"kmulherin@watrbx.wtf","IsEmailVerified":true,"AgeBracket":2,"UserAbove13":true}
+(RBXUserAccount*) UserAccountWithJSON:(NSDictionary*)json
{
RBXUserAccount* accountInfo = [[RBXUserAccount alloc] init];
accountInfo.userAbove13 = [json boolValueForKey:@"UserAbove13" withDefault:YES];
accountInfo.userId = [json numberForKey:@"UserId" withDefault:[NSNumber numberWithInt:1]];
accountInfo.email = [json stringForKey:@"UserEmail" withDefault:nil];
accountInfo.isEmailVerfied = [json boolValueForKey:@"IsEmailVerified" withDefault:NO];
accountInfo.userName = [json stringForKey:@"Name" withDefault:nil];
//accountInfo.ageBracket = [json numberForKey:@"AgeBracket" withDefault:[NSNumber numberWithInt:2]];
return accountInfo;
}
@end
@implementation RBXUserPresence
+(RBXUserPresence*) UserPresenceWithJSON:(NSDictionary *)json
{
RBXUserPresence* userPresence = [[RBXUserPresence alloc] init];
userPresence.gameID = [json stringForKey:@"GameId" withDefault:nil];
userPresence.isOnline = [json boolValueForKey:@"IsOnline"];
userPresence.lastOnlineTime = [json stringForKey:@"LastOnline"];
userPresence.lastOnlineLocation = [json stringForKey:@"LastLocation"];
userPresence.locationType = [json unsignedValueForKey:@"LocationType" withDefault:nil];
userPresence.placeID = [json unsignedValueForKey:@"PlaceId" withDefault:nil];
return userPresence;
}
@end
@implementation RBXUserAccountNotifications
+(RBXUserAccountNotifications*) UserAccountNotificationsWithJSON:(NSDictionary *)json
{
RBXUserAccountNotifications* notifications = [[RBXUserAccountNotifications alloc] init];
notifications.emailNotificationEnabled = [json boolValueForKey:@"EmailNotificationEnabled" withDefault:NO];
notifications.passwordNotificationEnabled = [json boolValueForKey:@"PasswordNotificationEnabled" withDefault:NO];
notifications.total = [json intValueForKey: @"Count" withDefault:0];
return notifications;
}
@end
@implementation RBXUserSearchInfo
+(RBXUserSearchInfo*) UserSearchInfoWithJSON:(NSDictionary *)json
{
RBXUserSearchInfo* user = [[RBXUserSearchInfo alloc] init];
user.avatarURL = [json stringForKey:@"AvatarUri"];
user.avatarIsFinal = [json boolValueForKey:@"AvatarFinal" withDefault:NO];
user.userId = [json numberForKey:@"UserId" withDefault:[NSNumber numberWithInt:-1]];
user.userName = [json stringForKey:@"Name" withDefault:@""];
user.blurb = [json stringForKey:@"Blurb" withDefault:@""];
user.previousNames = [json stringForKey:@"PreviousUserNamesCsv" withDefault:@""];
user.isOnline = [json boolValueForKey:@"IsOnline" withDefault:NO];
user.lastLocation = [json stringForKey:@"LastLocation" withDefault:@""];
user.profilePageURL = [json stringForKey:@"UserProfilePageUrl" withDefault:@"/User.aspx?id=-1"];
user.lastSeenDate = [json stringForKey:@"LastSeenDate" withDefault:@""];
return user;
}
@end
// Friend info
@implementation RBXFriendInfo
+(RBXFriendInfo*) FriendInfoWithJSON:(NSDictionary*)json
{
RBXFriendInfo* friend = [[RBXFriendInfo alloc] init];
friend.userID = [json numberForKey:@"UserId"];
friend.username = [json stringForKey:@"Username"];
friend.avatarURL = [json stringForKey:@"AvatarUri"];
friend.avatarIsFinal = [json boolValueForKey:@"AvatarFinal"];
friend.friendshipStatus = [json boolValueForKey:@"IsBestFriend"] == YES ? RBXFriendshipStatusBestFriends : RBXFriendshipStatusFriends;
friend.invitationID = [json unsignedValueForKey:@"InvitationId"];
NSDictionary* onlineStatus = [json dictionaryForKey:@"OnlineStatus" withDefault:nil];
if (onlineStatus)
friend.isOnline = [[onlineStatus stringForKey:@"ImageUrl"] isEqualToString:@"~/images/online.png"];
else
friend.isOnline = false;
return friend;
}
+(RBXFriendInfo*) FriendInfoFromFollower:(RBXFollower*)follower
{
RBXFriendInfo* friend = [[RBXFriendInfo alloc] init];
friend.userID = follower.userId;
friend.username = follower.username;
friend.avatarURL = follower.avatarURL;
friend.avatarIsFinal = follower.avatarIsFinal;
friend.friendshipStatus = RBXFriendshipStatusNonFriends;
friend.invitationID = nil;
friend.isOnline = follower.isOnline;
return friend;
}
@end
// Badge info
@implementation RBXBadgeInfo
+(RBXBadgeInfo*) parseGameBadgeFromJSON:(NSDictionary*)json
{
RBXBadgeInfo* badge = [[RBXBadgeInfo alloc] init];
badge.badgeAssetId = [NSString stringWithFormat:@"%lu", (unsigned long)[json unsignedValueForKey:@"BadgeAssetId"]];
badge.badgeCreatorId = [NSString stringWithFormat:@"%lu", (unsigned long)[json unsignedValueForKey:@"CreatorId"]];
badge.imageURL = [json stringForKey:@"ImageUrl" withDefault:nil];
if(badge.imageURL == nil)
badge.imageURL = [json stringForKey:@"ImageUri" withDefault:nil];
badge.isImageURLFinal = [json boolValueForKey:@"IsImageUrlFinal"];
badge.name = [json stringForKey:@"Name"];
badge.badgeDescription = [json stringForKey:@"Description"];
badge.isOwned = [json boolValueForKey:@"IsOwned"];
badge.badgeRarity = [json doubleValueForKey:@"Rarity"];
badge.badgeTotalAwardedEver = [json stringForKey:@"TotalAwarded"];
badge.badgeTotalAwardedYesterday = [json stringForKey:@"TotalAwardedYesterday"];
badge.badgeCreatedDate = [json stringForKey:@"Created"];
badge.badgeUpdatedDate = [json stringForKey:@"Updated"];
badge.badgeRarityName = [json stringForKey:@"RarityName"];
return badge;
}
@end
// Game Gear
@implementation RBXGameGear
@end
// Game Pass
@implementation RBXGamePass
@end
// Message info
@implementation RBXMessageInfo
+(RBXMessageInfo*) MessageWithJSON:(NSDictionary*)json
{
NSDictionary* recipient = [json dictionaryForKey:@"Recipient"];
//NSDictionary* recipientThumbnail = [json dictionaryForKey:@"RecipientThumbnail"];
NSDictionary* sender = [json dictionaryForKey:@"Sender"];
//NSDictionary* senderThumbnail = [json dictionaryForKey:@"SenderThumbnail"];
RBXMessageInfo* message = [[RBXMessageInfo alloc] init];
message.date = [json stringForKey:@"Created"];
message.messageID = [json unsignedValueForKey:@"Id"];
message.isRead = [json unsignedValueForKey:@"IsRead" withDefault:1] != 0;
//message.isReportAbuseDisplayed = [json unsignedValueForKey:@"IsReportAbuseDisplayed" withDefault:1] != 0;
//message.isSystemMessage = [json unsignedValueForKey:@"IsSystemMessage" withDefault:1] != 0;
message.recipientUserID = [recipient numberForKey:@"UserId"];
message.recipientUsername = [recipient stringForKey:@"UserName"];
message.senderUserID = [sender numberForKey:@"UserId"];
message.senderUsername = [sender stringForKey:@"UserName"];
message.subject = [json stringForKey:@"Subject"];
message.body = [[json stringForKey:@"Body"] stringByReplacingOccurrencesOfString:@"\n" withString:@" <br/>"];
return message;
}
+(NSMutableArray*) ArrayFromJSON:(NSDictionary*)json
{
NSMutableArray* messages = [NSMutableArray array];
NSArray* jsonMessages = [json arrayForKey:@"Collection"]; //[json arrayForKey:@"Messages"];
for(NSDictionary* jsonMessage in jsonMessages)
{
[messages addObject:[RBXMessageInfo MessageWithJSON:jsonMessage]];
}
return messages;
}
@end
// Followers and Following Info
@implementation RBXFollower
+(RBXFollower*) FollowerWithJSON:(NSDictionary*)json
{
RBXFollower* aFollower = [[RBXFollower alloc] init];
aFollower.userId = [json numberForKey:@"Id"];
aFollower.username = [json stringForKey:@"Username"];
aFollower.avatarIsFinal = [json boolValueForKey:@"AvatarFinal" withDefault:NO];
aFollower.avatarURL = [json stringForKey:@"AvatarUri"];
aFollower.isOnline = [json boolValueForKey:@"IsOnline" withDefault:NO];
return aFollower;
}
@end
//RBX Thumbnail
@implementation RBXThumbnail
+(RBXThumbnail*) ThumbnailWithJson:(NSDictionary*)json
{
RBXThumbnail* aThumbnail = [[RBXThumbnail alloc] init];
aThumbnail.assetId = [NSString stringWithFormat:@"%@", json[@"AssetId"]];
aThumbnail.assetHash = [NSString stringWithFormat:@"%@", json[@"AssetHash"]];
aThumbnail.assetTypeId = [json[@"AssetTypeId"] unsignedIntegerValue];
aThumbnail.assetURL = [NSString stringWithFormat:@"%@", json[@"Url"]];
aThumbnail.assetIsFinal = [json[@"IsFinal"] boolValue];
return aThumbnail;
}
@end
//RBX Notifications
@implementation RBXNotifications
+(RBXNotifications*) NotificationsWithJson:(NSDictionary *)json
{
RBXNotifications* allPlayerNotifications = [[RBXNotifications alloc] init];
allPlayerNotifications.unreadMessages = [json intValueForKey:@"unreadMessageCount" withDefault:0];
allPlayerNotifications.unansweredFriendRequests = [json intValueForKey:@"friendRequestsCount" withDefault:0];
return allPlayerNotifications;
}
@end
@implementation RBXSponsoredEvent
+(RBXSponsoredEvent*) SponsoredEventWithJson:(NSDictionary *)json
{
//[{"Name":"wintergames2015",
// "Title":"wintergames2015",
// "LogoImageURL":"http://images.watrbx.wtf/99bc31cc7d069159abb1e3e959a19724",
// "PageType":"Sponsored",
// "PageUrl":"/sponsored/wintergames2015"}]
RBXSponsoredEvent* event = [[RBXSponsoredEvent alloc] init];
event.eventName = [json stringForKey:@"Name" withDefault:@""];
event.eventTitle = [json stringForKey:@"Title" withDefault:@""];
event.eventLogoURLString = [json stringForKey:@"LogoImageURL" withDefault:nil];
event.eventPageType =[json stringForKey:@"PageType" withDefault:nil];
event.eventPageURLExtension = [json stringForKey:@"PageUrl" withDefault:nil];
return event;
}
+(NSMutableArray*) EventsWithJson:(NSArray *)jsonArray
{
NSMutableArray* events = [NSMutableArray array];
for (NSDictionary* jsonObj in jsonArray)
[events addObject:[RBXSponsoredEvent SponsoredEventWithJson:jsonObj]];
return events;
}
@end
//AB Test
@implementation RBXABTest
+(RBXABTest*) TestWithJSON:(NSDictionary *)json
{
RBXABTest* aTest = [[RBXABTest alloc] init];
aTest.experimentName = [json stringForKey:@"ExperimentName" withDefault:nil];
aTest.subjectType = [json intValueForKey:@"SubjectType" withDefault:nil];
aTest.subjectTargetId = [json numberForKey:@"SubjectTargetId" withDefault:nil];
aTest.variation = [json intValueForKey:@"Variation" withDefault:nil];
aTest.status = [json stringForKey:@"Status" withDefault:@"NoExperiment"];
return aTest;
}
+(NSDictionary*) TestsFromJSON:(NSArray*)json
{
if (!json)
return @{};
NSLog(@"AB Test JSON:");
NSLog(@"%@", json);
NSMutableDictionary* tests = [NSMutableDictionary dictionaryWithCapacity:json.count];
for (NSDictionary* jsonObj in json)
{
RBXABTest* aTest = [RBXABTest TestWithJSON:jsonObj];
if (aTest.experimentName)
[tests setObject:aTest forKey:aTest.experimentName];
}
return [tests copy];
}
- (BOOL) isLockedOn {
if ([self.status isEqualToString:@"LockedOn"]) {
return YES;
}
return NO;
}
- (id) initWithCoder:(NSCoder *)aDecoder {
if (self == [super init]) {
self.experimentName = [aDecoder decodeObjectForKey:@"experimentName"];
self.subjectType = [aDecoder decodeIntForKey:@"subjectType"];
self.subjectTargetId = [aDecoder decodeObjectForKey:@"subjectTargetId"];
self.variation = [aDecoder decodeIntForKey:@"variation"];
self.status = [aDecoder decodeObjectForKey:@"status"];
}
return self;
}
- (void) encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.experimentName forKey:@"experimentName"];
[aCoder encodeInt:self.subjectType forKey:@"subjectType"];
[aCoder encodeObject:self.subjectTargetId forKey:@"subjectTargetId"];
[aCoder encodeInt:self.variation forKey:@"variation"];
[aCoder encodeObject:self.status forKey:@"status"];
}
@end
// RobloxData
@implementation RobloxData
+ (void)initialize
{
[super initialize];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_completionQueue = dispatch_queue_create("wtf.watrbx.network_completion_queue", DISPATCH_QUEUE_CONCURRENT);
});
}
/* fetchRobloxImageURLWithURL: will poll the image url until it is marked as final,
or until
*/
+ (void) fetchRobloxImageURLWithURL:(NSString*)urlAsString intentID:(NSUInteger)intent withQueue:(NSOperationQueue*)queue completion:(void(^)(NSString* imageURL))handler
{
NSURL *url = [[NSURL alloc] initWithString:urlAsString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
BOOL isFinalImage = [responseObject boolValueForKey:@"Final"];
if(isFinalImage)
{
NSString* imageURL = [responseObject stringForKey:@"Url" withDefault:nil];
handler(imageURL);
}
else
{
// The image is still not generated.
// Schedule a request with a delay to test if its generation is completed
NSArray* delays = @[@1, @1, @2, @4, @8];
// Cut condition
if(intent < delays.count)
{
NSOperation* operation = [NSBlockOperation blockOperationWithBlock:^
{
[NSThread sleepForTimeInterval:[delays[intent] doubleValue]];
[RobloxData fetchRobloxImageURLWithURL:urlAsString intentID:(intent+1) withQueue:queue completion:handler];
}];
[queue addOperation:operation];
}
else
{
// Enough intents. Return the placeholder image
NSString* imageURL = [responseObject stringForKey:@"Url" withDefault:nil];
handler(imageURL);
}
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
[queue addOperation:operation];
}
/* fetchURLForAssetID: Retrieve the image URL for the given game
*/
+ (void) fetchURLForAssetID:(NSString*)assetID
withSize:(CGSize)size
completion:(void(^)(NSString* imageURL))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@asset-thumbnail/json?assetId=%@&width=%d&height=%d&format=jpeg",
[RobloxInfo getWWWBaseUrl],
assetID,
(int)size.width,
(int)size.height];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[RobloxData fetchRobloxImageURLWithURL:urlAsString intentID:0 withQueue:queue completion:handler];
}
+ (void) fetchThumbnailURLForGameID:(NSString*)assetID
withSize:(CGSize)size
completion:(void(^)(NSString* imageURL))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@asset-thumbnail/json?assetId=%@&width=%d&height=%d&format=jpeg&ignoreAssetMedia=true",
[RobloxInfo getWWWBaseUrl],
assetID,
(int)size.width,
(int)size.height];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[RobloxData fetchRobloxImageURLWithURL:urlAsString intentID:0 withQueue:queue completion:handler];
}
/* fetchThumbnailsForPlace: Retrieves an array of RBXThumbnails for a given game
*/
+ (void) fetchThumbnailsForPlace:(NSString*)placeID
withSize:(CGSize)size
completion:(void(^)(NSArray* thumbnails))handler
{
NSString* url = [NSString stringWithFormat:@"%@thumbnail/place-thumbnails/?placeId=%@&imageWidth=%d&imageHeight=%d&imageFormat=jpeg&ignoreAssetMedia=true",
[RobloxInfo getBaseUrl],
placeID,
(int)size.width,
(int)size.height];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* jsonResponse = responseObject;
NSArray* jsonThumbnails = [jsonResponse arrayForKey:@"thumbnails" withDefault:nil];
NSMutableArray* thumbnails = [NSMutableArray array];
for(NSDictionary* aThumbnail in jsonThumbnails)
{
[thumbnails addObject:[RBXThumbnail ThumbnailWithJson:aThumbnail]];
}
handler([thumbnails copy]);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler([[NSArray alloc] init]);
}];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
/* fetchAvatarURLForUserID: Retrieve the image URL for the given avatar ID
*/
+ (void) fetchAvatarURLForUserID:(NSUInteger)avatarID
withSize:(CGSize)size
completion:(void(^)(NSString* imageURL))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@avatar-thumbnail/json?userId=%u&width=%d&height=%d&format=png",
[RobloxInfo getBaseUrl],
(unsigned int)avatarID,
(int)size.width,
(int)size.height];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[RobloxData fetchRobloxImageURLWithURL:urlAsString intentID:0 withQueue:queue completion:handler];
}
/* Analytics Event Tracking functions:
*/
+(void) initializeBrowserTrackerWithCompletion:(void(^)(bool success, NSString* browserTracker))handler
{
//construct the url with a unique device identifier: the vendor ID
NSString* urlString = [NSString stringWithFormat:@"%@/device/initialize?mobileDeviceId=%@",
[RobloxInfo getApiBaseUrl],
[[[UIDevice currentDevice] identifierForVendor] UUIDString]];
[self hitEndpoint:urlString
isGetRequest:NO
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSDictionary* json = (NSDictionary*) responseObject;
if (json)
{
NSString* trackerID = [json stringForKey:@"browserTrackerId" withDefault:nil];
if (trackerID)
{
// Save the browser tracker Id
[self setBrowserTrackerId:trackerID];
handler(YES, trackerID);
return;
}
}
handler(NO, nil);
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error) {
handler(NO, nil);
}];
}
+ (NSString *) browserTrackerId
{
id obj = [[NSUserDefaults standardUserDefaults] objectForKey:BROWSER_TRACKER_KEY];
if (![RBXFunctions isEmpty:obj]) {
if ([obj isKindOfClass:[NSString class]]) {
return (NSString *)obj;
}
}
return nil;
}
+ (void) setBrowserTrackerId:(NSString *)trackerId {
NSString *oldTrackerId = [[NSUserDefaults standardUserDefaults] objectForKey:BROWSER_TRACKER_KEY];
if ([trackerId isEqualToString:oldTrackerId]) {
// New tracker is the same as the old tracker; no need to update
return;
}
[[NSUserDefaults standardUserDefaults] setObject:trackerId forKey:BROWSER_TRACKER_KEY];
[[NSUserDefaults standardUserDefaults] synchronize];
// 2015.0922 ajain - Report browser tracker change - we expect a tracker to be set upon app launch, so we do not report
// app launch setting of browser tracker, but after the browser tracker is set the first time, we do report subsequent changes
if (![RBXFunctions isEmptyString:oldTrackerId]) {
[[SessionReporter sharedInstance] reportSessionForContext:RBXAContextAppLaunch
result:RBXAResultSuccess
errorName:RBXAErrorNoError
responseCode:999
data:@{@"btid_changed":@(YES),
@"old_tracker_id":oldTrackerId,
@"new_tracker_id":trackerId}];
}
// Remove items tied to old tracker id
[[ABTestManager sharedInstance] removeStoredExperiments];
}
+ (void) reportEvent:(NSString*)event
withCompletion:(void(^)(bool success, NSError* err))completion
{
[self hitEndpoint:event
isGetRequest:YES
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
if (completion)
completion(YES, nil);
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error)
{
if (completion)
completion(NO, error);
}];
}
/* AB Testing functions:
*/
+ (NSDictionary*) fetchABTestEnrollments:(NSString*)experimentalData
{
if (!experimentalData)
return @{};
//configure the request
NSString* urlAsString = [[RobloxInfo getApiBaseUrl] stringByAppendingString:@"/ab/v1/get-enrollments"];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlAsString]];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:[experimentalData dataUsingEncoding:NSUTF8StringEncoding]];
//fire off the request
NSURLResponse* response;
NSError* error;
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
//check that we haven't gotten some error or bad response
if (!data || !response || ([(NSHTTPURLResponse*)response statusCode] != 200))
return @{};
//looks like we got a good response, parse it out and send it back
return [RBXABTest TestsFromJSON:[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]];
}
+ (NSDictionary*) enrollInABTests:(NSString*)experimentalData
{
if (!experimentalData)
return @{};
NSString* urlString = [[RobloxInfo getApiBaseUrl] stringByAppendingString:@"/ab/v1/enroll"];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:[experimentalData dataUsingEncoding:NSUTF8StringEncoding]];
//fire off the request
NSURLResponse* response;
NSError* error;
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
//check that we haven't gotten some error or bad response
if (!data || !response || ([(NSHTTPURLResponse*)response statusCode] != 200))
return @{};
//looks like we got a good response, parse it out and send it back
return [RBXABTest TestsFromJSON:[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]];
}
/* Sign Up and Login Functions:
*/
+(void) oldCheckIfValidUsername:(NSString*)username
completion:(void(^)(BOOL success, NSString* message))handler
{
//old url
NSString* url = [NSString stringWithFormat:@"%@/UserCheck/checkifinvalidusernameforsignup?username=%@",
[RobloxInfo getSecureBaseUrl],
username];
[self hitEndpoint:url
isGetRequest:YES
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* response = responseObject;
//old data looks like this:
//{
// "data": 1
//}
if ([[response objectForKey:@"data"] boolValue])
handler(NO, @"");
else
handler(YES, @"");
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error)
{
//if an error occurs with this endpoint, not the username itself,
// do not prevent the user from signing up, but still return the error message
if (handler)
handler(YES, error.description);
}];
}
+(void) checkIfValidUsername:(NSString*)username
completion:(void(^)(BOOL success, NSString* message))handler
{
//new url
NSString* url = [NSString stringWithFormat:@"%@/signup/is-username-valid?username=%@",
[RobloxInfo getApiBaseUrl],
username];
[self hitEndpoint:url
isGetRequest:YES
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* response = responseObject;
//new data - 10/15/2015
bool isValid = [response boolValueForKey:@"IsValid" withDefault:NO];
NSString* message = [response stringForKey:@"ErrorMessage" withDefault:@""];
if (handler)
handler(isValid, message);
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error)
{
//if an error occurs with this endpoint, not the username itself,
// do not prevent the user from signing up, but still return the error message
if (handler)
handler(YES, error.description);
}];
}
+(void) checkIfBlacklistedEmail:(NSString*)email
completion:(void(^)(BOOL isBlacklisted))handler
{
NSString* url = [NSString stringWithFormat:@"%@/UserCheck/checkifemailisblacklisted?email=%@",
[RobloxInfo getBaseUrl],
[email stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]];
[self hitEndpoint:url
isGetRequest:YES
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* json = responseObject;
bool isBlacklisted = NO;
if (json)
isBlacklisted = [json boolValueForKey:@"success" withDefault:NO];
handler(isBlacklisted);
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error)
{
//if there was a problem with this endpoint, do not block signups because of it
handler(NO);
}];
}
+(void) recommendUsername:(NSString*)usernameToTry
completion:(void(^)(BOOL success, NSString* newUsername))handler
{
NSString* url = [NSString stringWithFormat:@"%@/UserCheck/getrecommendedusername?usernameToTry=%@", [RobloxInfo getSecureBaseUrl], usernameToTry];
NSError* err;
NSString* usernameRecommendation = [NSString stringWithContentsOfURL:[NSURL URLWithString:url] encoding:NSUTF8StringEncoding error:&err];
if (!err && usernameRecommendation)
{
handler(YES, usernameRecommendation);
}
else
{
handler(NO, err.description);
}
}
+(void) oldCheckIfValidPassword:(NSString*)password
username:(NSString*)username
completion:(void(^)(BOOL success, NSString* message))handler
{
//Old url
NSString* url = [[RobloxInfo getSecureBaseUrl] stringByAppendingString:@"/UserCheck/validatepasswordforsignup?"];
NSString* args = [NSString stringWithFormat:@"password=%@&username=%@",password,username];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:[args dataUsingEncoding:NSUTF8StringEncoding]];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:
^(NSURLResponse *response, NSData *responseData, NSError *responseError)
{
if(!responseError)
{
NSDictionary* responseDict = [[NSDictionary alloc] init];
NSError* dictError = nil;
responseDict = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&dictError];
if(!dictError && responseDict)
{
bool success = [responseDict boolValueForKey:@"success" withDefault:NO];
if (success)
handler(YES, @"");
else
{
NSString* err = [responseDict stringForKey:@"error" withDefault:nil];
handler(NO, err);
}
}
else
handler(NO, nil);
}
else
handler(NO, nil);
}];
}
+(void) checkIfValidPassword:(NSString*)password
username:(NSString*)username
completion:(void(^)(BOOL success, NSString* message))handler
{
//new URL 10/15/2015
NSString* url = [NSString stringWithFormat:@"%@/signup/is-password-valid?username=%@&password=%@",
[RobloxInfo getApiBaseUrl], username, password];
[self hitEndpoint:url
isGetRequest:YES
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* json = responseObject;
if (json)
{
bool isValid = [json boolValueForKey:@"IsValid" withDefault:NO];
NSString* message = [json stringForKey:@"ErrorMessage" withDefault:nil];
if (handler)
handler(isValid, message);
}
else
{
if (handler)
handler(NO, nil);
}
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error)
{
if (handler)
handler(NO, error.description);
}];
}
/* Force Upgrade
*/
+ (void) checkForForceUpgrade:(NSString*)versionNumber
withCompletion:(void(^)(NSDictionary* response))handler;
{
NSString* urlString = [NSString stringWithFormat:@"%@mobileapi/check-app-version?appVersion=%@", [RobloxInfo getWWWBaseUrl], versionNumber];
[self hitEndpoint:urlString
isGetRequest:YES
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
handler(responseObject);
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
}
/* fetchDefaultSorts: Retrieves the selected sorts to display in the main page
*/
+ (void) fetchDefaultSorts:(NSUInteger)minimumGamesInSort
completion:(void(^)(NSArray* sorts)) handler
{
NSString* url = [NSString stringWithFormat:@"%@/games/default-sorts/?gamesRowLength=%d", [RobloxInfo getBaseUrl], (int)minimumGamesInSort];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSArray* jsonSorts = responseObject;
NSMutableArray* sorts = [NSMutableArray array];
for(NSDictionary* jsonSort in jsonSorts)
{
[sorts addObject:[RBXGameSort GameSortWithJSON:jsonSort]];
}
handler(sorts);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
/* fetchAllSorts: Retrieves the all the sorts
*/
+ (void) fetchAllSorts:(void(^)(NSArray* sorts)) completionHandler
{
NSString* url = [NSString stringWithFormat:@"%@/games/all-sorts", [RobloxInfo getBaseUrl]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
[request setValue:[RobloxInfo getUserAgentString] forHTTPHeaderField:@"User-Agent"];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSArray* jsonSorts = responseObject;
NSMutableArray* sorts = [NSMutableArray array];
for(NSDictionary* jsonSort in jsonSorts)
{
RBXGameSort* sort = [[RBXGameSort alloc] init];
sort.sortID = [jsonSort numberForKey:@"Id"];
sort.title = [jsonSort stringForKey:@"Name"];
[sorts addObject:sort];
}
completionHandler(sorts);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
completionHandler(nil);
}];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
/* fetchUserPlaces: Retrieves the user places
*/
+ (void) fetchUserPlaces:(NSNumber*)userID
startIndex:(NSUInteger)startIndex
numGames:(NSUInteger)numGames
thumbSize:(CGSize)thumbSize
completion:(void(^)(NSArray* games)) handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@/games/list-users-games-json?userId=%@&startIndex=%lu&pageSize=%lu&thumbWidth=%d&thumbHeight=%d&thumbFormat=png",
[RobloxInfo getBaseUrl],
[userID stringValue],
(unsigned long)startIndex,
(unsigned long)numGames,
(int)thumbSize.width,
(int)thumbSize.height];
NSURL *url = [[NSURL alloc] initWithString:urlAsString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSArray* jsonGames = (NSArray*) responseObject;
NSMutableArray* games = [[NSMutableArray alloc] init];
for(NSDictionary* jsonGame in jsonGames)
{
RBXGameData* game = [RBXGameData parseGameFromJSON:jsonGame];
[games addObject:game];
}
handler(games);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
/* fetchUserFavoriteGames: Retrieves the user favorite games
*/
+ (void) fetchUserFavoriteGames:(NSNumber*)userID
startIndex:(NSUInteger)startIndex
numGames:(NSUInteger)numGames
thumbSize:(CGSize)thumbSize
completion:(void(^)(NSArray* games)) handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@/games/list-users-favorite-games-json?userId=%@&startIndex=%lu&pageSize=%lu&thumbWidth=%d&thumbHeight=%d&thumbFormat=png",
[RobloxInfo getBaseUrl],
[userID stringValue],
(unsigned long)startIndex,
(unsigned long)numGames,
(int)thumbSize.width,
(int)thumbSize.height];
NSURL *url = [[NSURL alloc] initWithString:urlAsString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSArray* jsonGames = (NSArray*) responseObject;
NSMutableArray* games = [[NSMutableArray alloc] init];
for(NSDictionary* jsonGame in jsonGames)
{
RBXGameData* game = [RBXGameData parseGameFromJSON:jsonGame];
[games addObject:game];
}
handler(games);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
/* fetchGameList: Retrieves a list of games from the server
*/
+ (void) fetchGameListWithSortID:(NSNumber*)sortID
genreID:(NSNumber*)genreID
fromIndex:(NSUInteger)startIndex
numGames:(NSUInteger)numGames
thumbSize:(CGSize)thumbSize
completion:(void (^)(NSArray* games)) handler
{
[RobloxData fetchGameListWithSortID:sortID genreID:genreID playerID:nil fromIndex:startIndex numGames:numGames thumbSize:thumbSize completion:handler];
}
+ (void) fetchGameListWithSortID:(NSNumber*)sortID
genreID:(NSNumber*)genreID
playerID:(NSNumber*)playerID
fromIndex:(NSUInteger)startIndex
numGames:(NSUInteger)numGames
thumbSize:(CGSize)thumbSize
completion:(void (^)(NSArray* games)) handler
{
if( [sortID isEqualToNumber:[RBXGameSort MyGamesSort].sortID] )
{
[RobloxData fetchUserPlaces:playerID startIndex:startIndex numGames:numGames thumbSize:thumbSize completion:handler];
}
else if( [sortID isEqualToNumber:[RBXGameSort FavoriteGamesSort].sortID] )
{
[RobloxData fetchUserFavoriteGames:playerID startIndex:startIndex numGames:numGames thumbSize:thumbSize completion:handler];
}
else if( [sortID isEqualToNumber:[RBXGameSort DefaultSort].sortID] )
{
[self fetchGameListWithSortID:nil genreID:genreID playerID:playerID fromIndex:startIndex numGames:numGames thumbSize:thumbSize completion:handler];
}
else
{
NSMutableString* urlAsString = [NSMutableString stringWithFormat:@"%@/Games/List-Json?sortFilter=%d&startRows=%d&maxRows=%d&thumbWidth=%d&thumbHeight=%d&thumbFormat=jpeg",
[RobloxInfo getBaseUrl],
[sortID intValue],
(int)startIndex,
(int)numGames,
(int)thumbSize.width,
(int)thumbSize.height];
if (![RBXFunctions isEmpty:genreID]) {
[urlAsString appendString:[NSString stringWithFormat:@"&genreID=%ld", (long)[genreID integerValue]]];
}
NSURL *url = [[NSURL alloc] initWithString:urlAsString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSArray* jsonGames = (NSArray*) responseObject;
NSMutableArray* games = [NSMutableArray arrayWithCapacity:jsonGames.count];
for(NSDictionary* jsonGame in jsonGames)
{
RBXGameData* game = [RBXGameData parseGameFromJSON:jsonGame];
[games addObject:game];
}
handler(games);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
}
/* fetchGameDetails: Retrieve full game details
*/
+ (void) fetchGameDetails:(NSString*)placeID
completion:(void(^)(RBXGameData* game))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@places/api-get-details/?assetId=%@", [RobloxInfo getWWWBaseUrl], placeID];
NSURL *url = [[NSURL alloc] initWithString:urlAsString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* xmlGame = (NSDictionary*) responseObject;
RBXGameData* game = [[RBXGameData alloc] init];
game.placeID = placeID;
game.creatorName = [xmlGame stringForKey:@"Builder"];
game.dateCreated = [xmlGame stringForKey:@"Created"];
game.dateUpdated = [xmlGame stringForKey:@"Updated"];
game.gameDescription = [xmlGame stringForKey:@"Description"];
game.favorited = [xmlGame unsignedValueForKey:@"FavoritedCount"];
game.maxPlayers = [xmlGame unsignedValueForKey:@"MaxPlayers"];
game.title = [xmlGame stringForKey:@"Name"];
game.visited = [xmlGame unsignedValueForKey:@"VisitedCount"];
game.thumbnailURL = nil;
game.thumbnailIsFinal = false;
game.onlineCount = [xmlGame unsignedValueForKey:@"OnlineCount"];
game.assetGenre = [xmlGame stringForKey:@"AssetGenre"];
game.userFavorited = [xmlGame boolValueForKey:@"IsFavoritedByUser"];
game.universeID = [xmlGame numberForKey:@"UniverseId" withDefault:nil];
game.upVotes = [xmlGame unsignedValueForKey:@"TotalUpVotes"];
game.downVotes = [xmlGame unsignedValueForKey:@"TotalDownVotes"];
game.userOwns = NO;
game.productID = 0;
game.price = 0;
id userVote = [xmlGame objectForKey:@"UserVote"];
if(userVote != nil && [userVote isKindOfClass:[NSNumber class]] )
game.userVote = [userVote boolValue] == YES ? RBXUserVotePositive : RBXUserVoteNegative;
else
game.userVote = RBXUserVoteNoVote;
handler(game);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
/* fetchGameGear: Retrieve game gear
*/
+ (void) fetchGameGear:(NSString*)placeID
startIndex:(NSUInteger)startIndex
maxRows:(NSUInteger)maxRows
completion:(void(^)(NSArray* gear))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@PlaceItem/GetPlaceProductPromotions/?placeId=%@&startIndex=%d&maxRows=%d",
[RobloxInfo getBaseUrl],
placeID,
(int)startIndex,
(int)maxRows];
NSURL *url = [[NSURL alloc] initWithString:urlAsString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* jsonGear = (NSDictionary*) responseObject;
NSArray* gearList = jsonGear[@"data"];
NSMutableArray* result = [NSMutableArray array];
for(NSDictionary* gearData in gearList)
{
RBXGameGear* gear = [[RBXGameGear alloc] init];
gear.productID = [gearData numberForKey:@"ProductID"];
gear.assetID = [gearData numberForKey:@"AssetID"];
gear.name = [gearData stringForKey:@"Name"];
gear.gearDescription = [gearData stringForKey:@"Description"];
gear.sellerID = [gearData numberForKey:@"SellerID"];
gear.sellerName = [gearData stringForKey:@"SellerName"];
gear.totalSales = [gearData unsignedValueForKey:@"totalSales"];
gear.userOwns = [gearData boolValueForKey:@"UserOwns"];
gear.isRentable = [gearData boolValueForKey:@"IsRentable"];
gear.promotionID = [gearData numberForKey:@"PromotionID"];
gear.isForSale = [gearData boolValueForKey:@"IsForSale"];
gear.favoriteCount = [gearData unsignedValueForKey:@"TotalFavorites"];
gear.userFavorited = [gearData boolValueForKey:@"IsFavoritedByUser"];
gear.priceInRobux = [gearData unsignedValueForKey:@"PriceInRobux"];
gear.priceInTickets = [gearData unsignedValueForKey:@"PriceInTickets"];
[result addObject:gear];
}
handler(result);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
/* fetchGamePasses: Retrieve game passes
*/
+ (void) fetchGamePasses:(NSString*)placeID
startIndex:(NSUInteger)startIndex
maxRows:(NSUInteger)maxRows
completion:(void(^)(NSArray* passes))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@PlaceItem/GetGamePassesPaged/?placeId=%@&startIndex=%d&maxRows=%d",
[RobloxInfo getBaseUrl],
placeID,
(int)startIndex,
(int)maxRows];
NSURL *url = [[NSURL alloc] initWithString:urlAsString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* jsonPass = (NSDictionary*) responseObject;
NSArray* passList = jsonPass[@"data"];
NSMutableArray* result = [NSMutableArray array];
for(NSDictionary* passData in passList)
{
RBXGamePass* pass = [[RBXGamePass alloc] init];
pass.productID = [passData numberForKey:@"ProductID"];
pass.passID = [passData numberForKey:@"PassID"];
pass.passName = [passData stringForKey:@"PassName"];
pass.passDescription = [passData stringForKey:@"Description"];
pass.totalSales = [passData unsignedValueForKey:@"TotalSales"];
pass.upVotes = [passData unsignedValueForKey:@"TotalUpVotes"];
pass.downVotes = [passData unsignedValueForKey:@"TotalDownVotes"];
pass.userFavorited = [passData boolValueForKey:@"IsFavoritedByUser"];
pass.favoriteCount = [passData unsignedValueForKey:@"TotalFavorites"];
pass.userOwns = [passData boolValueForKey:@"UserOwns"];
pass.priceInRobux = [passData unsignedValueForKey:@"PriceInRobux"];
pass.priceInTickets = [passData unsignedValueForKey:@"PriceInTickets"];
id userVote = [passData objectForKey:@"UserVote"];
if(userVote != nil && [userVote isKindOfClass:[NSNumber class]] )
pass.userVote = [userVote boolValue] == YES ? RBXUserVotePositive : RBXUserVoteNegative;
else
pass.userVote = RBXUserVoteNoVote;
[result addObject:pass];
}
handler(result);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
+ (void) fetchGameBadges:(NSString*)placeID
completion:(void(^)(NSArray* badges))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@badges/list-badges-for-place?placeId=%@",
[RobloxInfo getBaseUrl],
placeID];
NSURL *url = [[NSURL alloc] initWithString:urlAsString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* jsonBadge = (NSDictionary*) responseObject;
if(jsonBadge != nil && [jsonBadge objectForKey:@"GameBadges"] != nil)
{
NSArray* passList = jsonBadge[@"GameBadges"];
NSMutableArray* result = [NSMutableArray array];
for(NSDictionary* badgeData in passList)
{
[result addObject:[RBXBadgeInfo parseGameBadgeFromJSON:badgeData]];
}
handler(result);
}
else
handler(nil);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
/* searchGames: Retrieves a list of games from the server
*/
+ (void) searchGames:(NSString*)keyword
fromIndex:(NSUInteger)startIndex
numGames:(NSUInteger)numGames
thumbSize:(CGSize)thumbSize
completion:(void (^)(NSArray* games)) handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@/Games/List-Json?keyword=%@&startRows=%d&maxRows=%d&thumbWidth=%d&thumbHeight=%d&thumbFormat=jpeg",
[RobloxInfo getWWWBaseUrl],
[keyword stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding],
(int)startIndex,
(int)numGames,
(int)thumbSize.width,
(int)thumbSize.height];
NSURL *url = [[NSURL alloc] initWithString:urlAsString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation
setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSArray* jsonGames = (NSArray*) responseObject;
NSMutableArray* games = [[NSMutableArray alloc] init];
for(NSDictionary* jsonGame in jsonGames)
{
RBXGameData* game = [[RBXGameData alloc] init];
game.players = [jsonGame stringForKey:@"PlayerCount"];
game.title = [jsonGame stringForKey:@"Name"];
game.creatorName = [jsonGame stringForKey:@"CreatorName"];
game.placeID = [jsonGame stringForKey:@"PlaceID"];
game.visited = [jsonGame unsignedValueForKey:@"Plays"];
game.thumbnailURL = [jsonGame stringForKey:@"ThumbnailUrl"];
game.thumbnailIsFinal = [jsonGame boolValueForKey:@"ThumbnailIsFinal"];
game.userFavorited = NO;
game.upVotes = [jsonGame unsignedValueForKey:@"TotalUpVotes"];
game.downVotes = [jsonGame unsignedValueForKey:@"TotalDownVotes"];
[games addObject:game];
}
handler(games);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
/* searchUsers: Retrieves a list of users from the server
*/
+ (void) searchUsers:(NSString*)keyword
fromIndex:(NSUInteger)startIndex
numUsers:(NSUInteger)numUsers
thumbSize:(CGSize)thumbSize
completion:(void (^)(NSArray* users)) handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@/search/search-users-json?keyword=%@&includeAvatar=true&startRows=%d&maxRows=%d&imgWidth=%d&imgHeight=%d&imgFormat=jpeg",
[RobloxInfo getWWWBaseUrl],
[keyword stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding],
(int)startIndex,
(int)numUsers,
(int)thumbSize.width,
(int)thumbSize.height];
[self hitEndpoint:urlAsString
isGetRequest:YES
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
//parse the responseObject. It looks something like this:
//"Keyword": "imightbelying",
//"StartRow": 0,
//"MaxRows": 10,
//"UserSearchResults": [
// {
// "AvatarUri": "http://t2.watrbx.wtf/d7882cb26ca4a298b386c9a4b1cbb24c",
// "AvatarFinal": true,
// "UserId": 68465808,
// "Name": "iMightBeLying",
// "Blurb": "a really long string with /n and other characters",
// "PreviousUserNamesCsv": "",
// "IsOnline": true,
// "LastLocation": "Website",
// "UserProfilePageUrl": "/User.aspx?id=68465808",
// "LastSeenDate": "1/14/2015 12:04 PM"
// }
//]
NSDictionary* json = responseObject;
NSMutableArray* users = [NSMutableArray arrayWithCapacity:[json intValueForKey:@"MaxRows"]];
NSArray* jsonUsers = [json arrayForKey:@"UserSearchResults" withDefault:@[]];
for (int i = 0; i < jsonUsers.count; i++)
{
[users addObject:[RBXUserSearchInfo UserSearchInfoWithJSON:jsonUsers[i]]];
}
handler([users copy]);
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error)
{
//something went wrong, return an empty array
handler(@[]);
}];
}
/* fetchUserLeaderboardInfo: Retrieve the leaderboard info for a specific game and the current logged in user.
Returns null if there is no session active or there was an error in the request.
*/
+ (void) fetchUserLeaderboardInfo:(RBXLeaderboardsTarget)target
userID:(NSNumber*)currentUserID
distributorID:(NSNumber*)distributorID
timeFilter:(RBXLeaderboardsTimeFilter)time
avatarSize:(CGSize)avatarSize
completion:(void(^)(RBXLeaderboardEntry* userEntry))handler
{
//example
//http://www.watrbx.wtf/leaderboards/rank/json?targetType=0&distributorTargetId=65241&timeFilter=0&max=1&imgWidth=30&imgHeight=30&imgFormat=png
//{
// "Rank": 144,
// "DisplayRank": "144",
// "FullRank": null,
// "WasRankTruncated": false,
// "Name": "iMightBeLying",
// "UserId": 68465808,
// "TargetId": 68465808,
// "ProfileUri": "/User.aspx?ID=68465808",
// "ClanName": null,
// "ClanUri": null,
// "Points": 204,
// "DisplayPoints": "204",
// "FullPoints": null,
// "WasPointsTruncated": false,
// "ClanEmblemID": 0,
// "UserImageUri": "http://t6.watrbx.wtf/74dc9e800fde9bea6c4e512860283620",
// "UserImageFinal": true,
// "ClanImageUri": "",
// "ClanImageFinal": false
//}
NSString* urlAsString = [NSString stringWithFormat: @"%@leaderboards/rank/json/?targetType=%lu"
@"&distributorTargetId=%ld"
@"&timeFilter=%lu"
@"&max=2"
@"&imgWidth=%d&imgHeight=%d&imgFormat=png",
[RobloxInfo getBaseUrl],
(unsigned long)target,
(long)(distributorID != nil ? [distributorID integerValue] : 0),
(unsigned long)time,
(int)avatarSize.width,
(int)avatarSize.height];
NSURL *url = [[NSURL alloc] initWithString:urlAsString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSArray* jsonResults = (NSArray*) responseObject;
// Find the user entry in the results
NSDictionary* jsonUserEntry = nil;
for(NSDictionary* jsonEntry in jsonResults)
{
NSNumber* userID = [jsonEntry numberForKey:@"UserId"];
if([userID isEqualToNumber:currentUserID])
{
jsonUserEntry = jsonEntry;
break;
}
}
// return the parsed result if there is one
handler(jsonUserEntry != nil ? [RBXLeaderboardEntry parseLeaderboardEntry:jsonUserEntry] : nil);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
/* fetchLeaderboards: Retrieve leaderboards for a specific game
*/
+ (void) fetchLeaderboardsFor:(RBXLeaderboardsTarget)target
timeFilter:(RBXLeaderboardsTimeFilter)time
distributorID:(NSNumber*)distributorID
startIndex:(NSUInteger)startIndex
numItems:(NSUInteger)numItems
lastEntry:(RBXLeaderboardEntry*)lastEntry
avatarSize:(CGSize)avatarSize
completion:(void(^)(NSArray* leaderboard))handler
{
///{
/// "Rank": 1,
/// "DisplayRank": "1",
/// "FullRank": null,
/// "WasRankTruncated": false,
/// "Name": "balidhan",
/// "UserId": 31106566,
/// "TargetId": 31106566,
/// "ProfileUri": "/User.aspx?ID=31106566",
/// "ClanName": null,
/// "ClanUri": null,
/// "Points": 3657,
/// "DisplayPoints": "3,657",
/// "FullPoints": null,
/// "WasPointsTruncated": false,
/// "ClanEmblemID": 0,
/// "UserImageUri": "http://t7.watrbx.wtf/85136625f88cd07dd4e22b2b7d7a75b8",
/// "UserImageFinal": true,
/// "ClanImageUri": "",
/// "ClanImageFinal": false
///}
NSString* urlAsString = [NSString stringWithFormat:@"%@leaderboards/game/json/?targetType=%lu"
@"&distributorTargetId=%ld"
@"&timeFilter=%lu"
@"&startIndex=%lu&max=%lu"
@"&currentRank=%lu"
@"&previousPoints=%lu"
@"&imgWidth=%d&imgHeight=%d&imgFormat=png",
[RobloxInfo getBaseUrl],
(unsigned long)target,
(long)(distributorID != nil ? [distributorID integerValue] : 0),
(unsigned long)time,
(unsigned long)startIndex,
(unsigned long)numItems,
(unsigned long)(lastEntry != nil ? lastEntry.rank : 1),
(unsigned long)(lastEntry != nil ? lastEntry.points : 0),
(int)avatarSize.width,
(int)avatarSize.height];
NSURL *url = [[NSURL alloc] initWithString:urlAsString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSArray* jsonResults = (NSArray*) responseObject;
NSMutableArray* leaderboard = [NSMutableArray arrayWithCapacity:jsonResults.count];
for(NSDictionary* jsonEntry in jsonResults)
{
RBXLeaderboardEntry* entry = [RBXLeaderboardEntry parseLeaderboardEntry:jsonEntry];
[leaderboard addObject:entry];
}
handler(leaderboard);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
/* fetchMyProfileWithSize: Retrieve current user profile info
*/
+ (void) fetchMyProfileWithSize:(CGSize)avatarSize
completion:(void(^)(RBXUserProfileInfo* profile))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@my/profile?imgWidth=%d&imgHeight=%d",
[RobloxInfo getBaseUrl],
(int)avatarSize.width,
(int)avatarSize.height];
NSURL *url = [[NSURL alloc] initWithString:urlAsString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* jsonResult = responseObject;
handler([RBXUserProfileInfo UserProfileInfoWithJSON:jsonResult]);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
/* fetchUserProfile: Retrieve a user profile info
*/
+ (void) fetchUserProfile:(NSNumber*)userID
avatarSize:(CGSize)avatarSize
completion:(void(^)(RBXUserProfileInfo* profile))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@profile?userId=%d&imgWidth=%d&imgHeight=%d",
[RobloxInfo getBaseUrl],
[userID intValue],
(int)avatarSize.width,
(int)avatarSize.height];
[self hitEndpoint:urlAsString
isGetRequest:YES
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* jsonResult = responseObject;
handler([RBXUserProfileInfo UserProfileInfoWithJSON:jsonResult]);
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
}
/* fetchUserFriends
*/
+ (void) fetchUserFriends:(NSNumber*)userID
friendType:(RBXFriendType)friendType
startIndex:(NSUInteger)startIndex
numItems:(NSUInteger)numItems
avatarSize:(CGSize)avatarSize
completion:(void(^)(NSUInteger totalFriends, NSArray* friends))handler
{
NSString* friendTypeStr = nil;
switch (friendType)
{
case RBXFriendTypeAllFriends: friendTypeStr = @"AllFriends"; break;
case RBXFriendTypeRegularFriend: friendTypeStr = @"RegularFriends"; break;
case RBXFriendTypeBestFriend: friendTypeStr = @"BestFriends"; break;
case RBXFriendTypeFriendRequest: friendTypeStr = @"FriendRequests"; break;
}
// friendsType: AllFriends, RegularFriends, BestFriends
NSString* urlAsString = [NSString stringWithFormat:@"%@friends/json?userId=%d&currentPage=%lu&pageSize=%lu&imgWidth=%d&imgHeight=%d&imgFormat=jpeg&friendsType=%@",
[RobloxInfo getBaseUrl],
[userID intValue],
(unsigned long)startIndex,
(unsigned long)numItems,
(int)avatarSize.width,
(int)avatarSize.height,
friendTypeStr];
NSURL *url = [[NSURL alloc] initWithString:urlAsString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* jsonResult = responseObject;
NSArray* jsonFriends = jsonResult[@"Friends"];
NSUInteger totalFriends = [jsonResult[@"TotalFriends"] integerValue];
if(jsonFriends)
{
NSMutableArray* friends = [[NSMutableArray alloc] initWithCapacity:jsonFriends.count];
for(NSDictionary* jsonFriend in jsonFriends)
{
[friends addObject:[RBXFriendInfo FriendInfoWithJSON:jsonFriend]];
}
handler(totalFriends, friends);
}
else
{
handler(totalFriends, nil);
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(0, nil);
}];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
/* fetchUserBadges
*/
+ (void) fetchUserBadges:(RBXUserBadgeType)badgeType
forUser:(NSNumber*)userID
badgeSize:(CGSize)badgeSize
completion:(void(^)(NSArray* badges))handler
{
// friendsType: AllFriends, RegularFriends, BestFriends
NSString* urlAsString = [NSString stringWithFormat:@"%@badges/%@?userId=%d&imgWidth=%d&imgHeight=%d&imgFormat=png",
[RobloxInfo getBaseUrl],
(badgeType == RBXUserBadgeTypePlayer) ? @"player" : @"roblox",
[userID intValue],
(int)badgeSize.width,
(int)badgeSize.height];
NSURL *url = [[NSURL alloc] initWithString:urlAsString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* jsonResults = responseObject;
if(jsonResults)
{
NSArray* jsonBadges = [NSArray array];
if (badgeType == RBXUserBadgeTypeRoblox)
{
jsonBadges = [jsonResults arrayForKey:@"RobloxBadges"];
}
else if (badgeType == RBXUserBadgeTypePlayer)
{
jsonBadges = [jsonResults arrayForKey:@"PlayerBadges"];
}
NSMutableArray* badges = [[NSMutableArray alloc] initWithCapacity:jsonBadges.count];
for(NSDictionary* jsonBadge in jsonBadges)
{
[badges addObject:[RBXBadgeInfo parseGameBadgeFromJSON:jsonBadge]];
}
handler(badges);
}
else
{
handler(nil);
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
/* acceptFriendRequest - Actively phasing out in favor for API proxy calls
*/
+ (void) acceptFriendRequest:(NSUInteger)invitationID
withTargetUserID:(NSUInteger)targetUserID
completion:(void(^)(BOOL success))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@api/friends/acceptfriendrequest?invitationID=%lu&targetUserID=%lu", [RobloxInfo getBaseUrl], (unsigned long)invitationID, (unsigned long)targetUserID];
RobloxXSRFRequest* request = [[RobloxXSRFRequest alloc] initWithBaseURL:nil];
[request XSRFPOST:urlAsString parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
handler(YES);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO);
}];
}
/* declineFriendRequest - Actively phasing out in favor for API proxy calls
*/
+ (void) declineFriendRequest:(NSUInteger)invitationID
withTargetUserID:(NSUInteger)targetUserID
completion:(void(^)(BOOL success))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@api/friends/declinefriendrequest?invitationID=%lu&targetUserID=%lu", [RobloxInfo getBaseUrl], (unsigned long)invitationID, (unsigned long)targetUserID];
RobloxXSRFRequest* request = [[RobloxXSRFRequest alloc] initWithBaseURL:nil];
[request XSRFPOST:urlAsString parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
handler(YES);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO);
}];
}
/* addFriend - Actively phasing out in favor for API proxy calls
*/
+ (void) sendFriendRequest:(NSNumber*)userID
completion:(void(^)(BOOL success))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@api/friends/sendfriendrequest?targetUserID=%lu",
[RobloxInfo getBaseUrl],
(unsigned long)[userID unsignedIntegerValue]];
RobloxXSRFRequest* request = [[RobloxXSRFRequest alloc] initWithBaseURL:nil];
[request XSRFPOST:urlAsString parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
handler(YES);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO);
}];
}
/* request friendship - API Proxy alternative to sending a friendship request
*/
+ (void) requestFrienshipWithUserID:(NSNumber*)friendUserID
completion:(void(^)(BOOL success))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@/user/request-friendship?recipientUserId=%ld", [RobloxInfo getApiBaseUrl], (long)[friendUserID integerValue]];
RobloxXSRFRequest* request = [[RobloxXSRFRequest alloc] initWithBaseURL:nil];
[request XSRFPOST:urlAsString parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
handler(YES);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO);
}];
}
/* removeFriend - Actively phasing out in favor for API proxy calls
*/
+ (void) removeFriend:(NSNumber*)userID
completion:(void(^)(BOOL success))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@api/friends/removefriend?targetUserID=%lu",
[RobloxInfo getBaseUrl],
(unsigned long)[userID unsignedIntegerValue]];
RobloxXSRFRequest* request = [[RobloxXSRFRequest alloc] initWithBaseURL:nil];
[request XSRFPOST:urlAsString parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
handler(YES);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO);
}];
}
/* unfriend - API proxy equivalent to removeFriend
*/
+ (void) unfriend:(NSNumber*)userID
completion:(void(^)(BOOL success))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@/user/unfriend?friendUserId=%lu",
[RobloxInfo getApiBaseUrl],
(unsigned long)[userID unsignedIntegerValue]];
RobloxXSRFRequest* request = [[RobloxXSRFRequest alloc] initWithBaseURL:nil];
[request XSRFPOST:urlAsString parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
handler(YES);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO);
}];
}
/* makeBestFriend - Deprecated
*/
+ (void) makeBestFriend:(NSNumber*)userID
completion:(void(^)(BOOL success))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@api/friends/addbestfriend?targetUserID=%lu",
[RobloxInfo getBaseUrl],
(unsigned long)[userID unsignedIntegerValue]];
RobloxXSRFRequest* request = [[RobloxXSRFRequest alloc] initWithBaseURL:nil];
[request XSRFPOST:urlAsString parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
//parse the result before blindly returning yes
handler(YES);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO);
}];
}
/* removeBestFriend - Deprecated
*/
+ (void) removeBestFriend:(NSNumber*)userID
completion:(void(^)(BOOL success))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@api/friends/removebestfriend?targetUserID=%lu",
[RobloxInfo getBaseUrl],
(unsigned long)[userID unsignedIntegerValue]];
RobloxXSRFRequest* request = [[RobloxXSRFRequest alloc] initWithBaseURL:nil];
[request XSRFPOST:urlAsString parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
//parse the result before blindly returning yes
handler(YES);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO);
}];
}
/* followUser
*/
+ (void) followUser:(NSNumber *)userID
completion:(void (^)(BOOL))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@/user/follow?followedUserId=%ld", [RobloxInfo getApiBaseUrl], (long)userID.integerValue];
RobloxXSRFRequest* request = [[RobloxXSRFRequest alloc] initWithBaseURL:nil];
[request XSRFPOST:urlAsString parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
//responseObject JSON should look like this
//{
// message = Success; //some string
// success = 1; //some boolean
//}
BOOL successfulRequest = [responseObject boolValueForKey:@"success" withDefault:NO];
handler(successfulRequest);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO);
}];
}
/* unfollowUser
*/
+ (void) unfollowUser:(NSNumber *)userID
completion:(void (^)(BOOL))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@/user/unfollow?followedUserId=%ld", [RobloxInfo getApiBaseUrl], (long)userID.integerValue];
RobloxXSRFRequest* request = [[RobloxXSRFRequest alloc] initWithBaseURL:nil];
[request XSRFPOST:urlAsString parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* jsonResults = responseObject;
if (jsonResults)
{
//responseObject JSON should look like this
//{
// message = Success; //some string
// success = 1; //some boolean
//}
BOOL successfulRequest = [responseObject boolValueForKey:@"success" withDefault:NO];
handler(successfulRequest);
}
else
{
handler(NO);
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO);
}];
}
/* fetch count of friends
*/
+ (void) fetchFriendCount:(NSNumber*)currentUserId
withCompletion:(void(^)(BOOL success, NSString* message, int count))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@/user/get-friendship-count?userId=%ld",
[RobloxInfo getApiBaseUrl],
(long)currentUserId.integerValue];
[self hitEndpoint:urlAsString
isGetRequest:YES
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* json = responseObject;
if (json)
{
bool success = [json boolValueForKey:@"success" withDefault:NO];
NSString* message = [json stringForKey:@"message" withDefault:@"Failure"];
int count = [json intValueForKey:@"count" withDefault:-1];
handler(success, message, count);
return;
}
//else
handler(false, @"Failure", -1);
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(false, @"Failure", -1);
}];
}
/* fetch a user's followers
*/
+ (void) fetchFollowersForUser:(NSNumber*)userID
atPage:(int)userPage
avatarSize:(CGSize)avatarSize
withCompletion:(void(^)(bool success, NSArray* followers))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@/users/followers?userId=%ld&page=%d&imageWidth=%d&imageHeight=%d&imageFormat=jpeg",
[RobloxInfo getApiBaseUrl], (long)userID.integerValue, userPage, (int)avatarSize.width, (int)avatarSize.height];
[self hitEndpoint:urlAsString
isGetRequest:YES
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSArray* people = responseObject;
if (people.count > 0)
{
NSMutableArray* followers = [NSMutableArray arrayWithCapacity:people.count];
for (int i = 0; i < people.count; i++)
{
RBXFollower* follower = [RBXFollower FollowerWithJSON:people[i]];
//this can be cleaned up by moving the initialization code to the RBXFriendInfo
[followers addObject:[RBXFriendInfo FriendInfoFromFollower:follower]];
}
handler(YES, [followers copy]);
}
else { handler(NO, @[]); }
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO, @[]);
}];
}
/* fetch all the users that a user is following
*/
+ (void) fetchMyFollowingAtPage:(int)userPage
avatarSize:(CGSize)avatarSize
withCompletion:(void(^)(bool success, NSArray* following))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@/users/followings?page=%d&imageWidth=%d&imageHeight=%d&imageFormat=jpeg",
[RobloxInfo getApiBaseUrl], userPage, (int)avatarSize.width, (int)avatarSize.height];
[self hitEndpoint:urlAsString
isGetRequest:YES
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSArray* people = responseObject;
if (people.count > 0)
{
NSMutableArray* following = [NSMutableArray arrayWithCapacity:people.count];
for (int i = 0; i < people.count; i++)
{
RBXFollower* follower = [RBXFollower FollowerWithJSON:people[i]];
//this can be cleaned up by moving the initialization code to the RBXFriendInfo
[following addObject:[RBXFriendInfo FriendInfoFromFollower:follower]];
}
handler(YES, [following copy]);
}
else { handler(NO, @[]); }
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO, @[]);
}];
}
/* changeUserPassword
*/
+ (void) changeUserOldPassword:(NSString*)passwordOld
toNewPassword:(NSString*)passwordNew
withConfirmation:(NSString*)passwordConfirm
andCompletion:(void(^)(BOOL success, NSString* message))handler
{
//submit a message to the server to request that the current player's password be changed
//send an https post request to /account/changepassword
//XSRF Token required
//Parameters:
// oldPassword - users current password
// newPassword - new password
// confirmNewPassword - same as new password. must match.
//Returns JSON object with properties:
// Success: true if password was changed
// Message: error message, or empty string if successful
// sl_translate: just ignore this
//compile request parameters into a dictionary
NSDictionary *requestParams = [NSDictionary dictionaryWithObjects:@[passwordOld, passwordNew, passwordConfirm]
forKeys:@[@"oldPassword", @"newPassword", @"confirmNewPassword"]];
//create the url and secure it with https
NSString* newPasswordURLString = [[RobloxInfo getWWWBaseUrl] stringByAppendingString:@"account/changepassword"];
newPasswordURLString = [newPasswordURLString stringByReplacingOccurrencesOfString:@"http:" withString:@"https:"];
//send the request and parse the response
RobloxXSRFRequest* request = [[RobloxXSRFRequest alloc] initWithBaseURL:nil];
[request XSRFPOST:newPasswordURLString parameters:requestParams
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* dict = responseObject;
bool wasSuccessful = [dict unsignedValueForKey:@"Success"] == 1;
if (wasSuccessful)
handler(YES, NSLocalizedString(@"SuccessChangePassword", nil));
else
handler(NO, [dict stringForKey:@"Message"]);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO, NSLocalizedString(@"ErrorUnknownPasswordChange", nil));
}];
}
/* changeUserEmail
*/
+ (void) changeUserEmail:(NSString*)email
withPassword:(NSString*)password
andCompletion:(void(^)(BOOL success, NSString* message))handler
{
//submit a message to the server to request that the current player's email be changed
//send an https post request to the url : /account/changeemail
//XSRF Token required
//parameters :
// emailAddress - new email address
// password - users current password
//Returns JSON object with properties:
// Success: true if email was changed
// Message: error message, or “Email Added” if successful
// sl_translate: just ignore this
//compile inputs into a dictionary
NSDictionary *requestParams = [NSDictionary dictionaryWithObjects:@[email, password]
forKeys:@[@"emailAddress", @"password"]];
//create the url and secure it with https
NSString* emailURLString = [[RobloxInfo getWWWBaseUrl] stringByAppendingString:@"account/changeemail"];
emailURLString = [emailURLString stringByReplacingOccurrencesOfString:@"http:" withString:@"https:"];
//send the request and parse the response
RobloxXSRFRequest* request = [[RobloxXSRFRequest alloc] initWithBaseURL:nil];
[request XSRFPOST:emailURLString parameters:requestParams
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* dict = responseObject;
bool wasSuccessful = [dict unsignedValueForKey:@"Success"] == 1;
if (wasSuccessful)
handler(YES, NSLocalizedString(@"SuccessChangeEmail", nil));
else
handler(NO, [dict stringForKey:@"Message"]);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO, NSLocalizedString(@"ErrorUnknownEmailChange", nil));
}];
}
/* fetch My Account
*/
+ (void) fetchMyAccountWithCompletion:(void(^)(RBXUserAccount* account))handler
{
NSString* urlAsString = [[RobloxInfo getWWWBaseUrl] stringByAppendingString:@"/my/account/json"];
[self hitEndpoint:urlAsString
isGetRequest:YES
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
handler([RBXUserAccount UserAccountWithJSON:responseObject]);
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
}
+ (void) fetchUserHasSetPasswordWithCompletion:(void(^)(bool passwordSet))handler
{
NSString* urlString = [[[RobloxInfo getApiBaseUrl] stringByReplacingOccurrencesOfString:@"http://" withString:@"https://"] stringByAppendingString:@"/social/has-user-set-password"];
[self hitEndpoint:urlString
isGetRequest:YES
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSDictionary* json = (NSDictionary*)responseObject;
if ([[json stringForKey:@"status"] isEqualToString:@"success"])
{
bool isConnected = [[[json stringForKey:@"result" withDefault:@"false"] lowercaseString] isEqualToString:@"true"];
if (handler)
handler(isConnected);
}
else
{
if (handler)
handler(YES); //DEFAULT SHOULD BE YES
}
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (handler)
handler(YES); //DEFAULT SHOULD BE YES
}];
}
/* fetch My Account Notifications
*/
+ (void) fetchAccountNotificationsWithCompletion:(void(^)(RBXUserAccountNotifications* notifications))handler
{
NSString* urlString = [[RobloxInfo getApiBaseUrl] stringByAppendingString:@"/notifications/account"];
[RobloxData hitEndpoint:urlString
isGetRequest:YES
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
handler([RBXUserAccountNotifications UserAccountNotificationsWithJSON:responseObject]);
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler([RBXUserAccountNotifications UserAccountNotificationsWithJSON:nil]);
}];
}
/* fetch User Presence
*/
+ (void) fetchPresenceForUser:(NSNumber*)userID
withCompletion:(void(^)(RBXUserPresence*))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@/users/%d/onlinestatus", [RobloxInfo getApiBaseUrl], userID.intValue];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlAsString]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
handler([RBXUserPresence UserPresenceWithJSON:responseObject]);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
//functions handling this should check for this result
handler(nil);
}];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
/* fetchMessages: Retrieve user messages for the specified message type
*/
+ (void) fetchMessages:(RBXMessageType)messageType
pageNumber:(NSUInteger)pageNumber
pageSize:(NSUInteger)pageSize
completion:(void(^)(NSArray* messages))handler
{
NSString* messageTypeString = @"";
switch (messageType)
{
case RBXMessageTypeInbox: messageTypeString = @"Inbox"; break;
case RBXMessageTypeSent: messageTypeString = @"Sent"; break;
case RBXMessageTypeArchive: messageTypeString = @"Archive"; break;
case RBXMessageTypeAnnouncements: messageTypeString = @"Announcements"; break;
}
// friendsType: AllFriends, RegularFriends, BestFriends
NSString* urlAsString = [NSString stringWithFormat:@"%@messages/api/get-messages?pageNumber=%lu&pageSize=%lu&MessageTab=%@",
[RobloxInfo getBaseUrl],
(unsigned long)pageNumber,
(unsigned long)pageSize,
messageTypeString];
[RobloxData hitEndpoint:urlAsString
isGetRequest:YES
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* jsonResults = responseObject;
if(jsonResults)
handler([RBXMessageInfo ArrayFromJSON:jsonResults]);
else
handler(nil);
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
}
/* fetchNotifications: Retrieve user notifications
*/
+ (void) fetchNotificationsWithCompletion:(void(^)(NSArray* messages))handler
{
// friendsType: AllFriends, RegularFriends, BestFriends
NSString* urlAsString = [NSString stringWithFormat:@"%@notifications/api/get-notifications", [RobloxInfo getBaseUrl]];
NSURL *url = [[NSURL alloc] initWithString:urlAsString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary* jsonResults = responseObject;
if(jsonResults)
{
NSMutableArray* messages = [NSMutableArray array];
NSArray* collection = [jsonResults arrayForKey:@"Collection"];
for(NSDictionary* jsonMessage in collection)
{
NSDictionary* sender = [jsonMessage dictionaryForKey:@"Sender"];
//NSDictionary* senderThumbnail = [jsonMessage dictionaryForKey:@"SenderThumbnail"];
RBXMessageInfo* message = [[RBXMessageInfo alloc] init];
message.date = [jsonMessage stringForKey:@"Created"];
//messages.dateUpdated = [jsonMessage stringForKey:@"Updated"];
message.isRead = [jsonMessage unsignedValueForKey:@"IsRead"] != 0;
message.recipientUserID = [jsonMessage numberForKey:@"RecipientUserId"];
message.recipientUsername = [jsonMessage stringForKey:@"RecipientUserName"];
message.senderUserID = [sender numberForKey:@"UserId"];
message.senderUsername = [sender stringForKey:@"UserName"];
message.messageID = [jsonMessage unsignedValueForKey:@"Id"];
message.subject = [jsonMessage stringForKey:@"Subject"];
message.body = [jsonMessage stringForKey:@"Body"];
[messages addObject:message];
}
handler(messages);
}
else
{
handler(nil);
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
/* markMessageAsRead: Mark the specified message as read
*/
+ (void) markMessageAsRead:(NSUInteger)messageID completion:(void(^)(BOOL success))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@messages/api/mark-messages-read", [RobloxInfo getBaseUrl]];
NSDictionary* message = @{@"messageIds": @[[NSNumber numberWithInteger:messageID]] };
RobloxXSRFRequest* request = [[RobloxXSRFRequest alloc] initWithBaseURL:nil];
request.requestSerializer = [AFJSONRequestSerializer serializer];
[request XSRFPOST:urlAsString parameters:message
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
handler(YES);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO);
}];
}
/* fetchTotalNotificationsForUser: WithCompletion: Retrieve a count of unread messages, system notifications, and outstanding friend requests
*/
+ (void) fetchTotalNotificationsForUser:(NSNumber*)userID WithCompletion:(void(^)(RBXNotifications* notifications))handler;
{
//NSString* urlAsString = [NSString stringWithFormat:@"%@messages/api/get-my-unread-messages-count", [RobloxInfo getBaseUrl]];
NSString* urlAsString = [NSString stringWithFormat:@"%@/incoming-items/counts", [RobloxInfo getApiBaseUrl]];
[RobloxData hitEndpoint:urlAsString
isGetRequest:YES
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
handler([RBXNotifications NotificationsWithJson:responseObject]);
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
}
/* fetchSponsoredEvents: Retrieve a list of Roblox's Sponsored and Holiday Events
*/
+ (void) fetchSponsoredEvents:(void (^)(NSArray *))handler
{
NSString* urlAsString = [[RobloxInfo getWWWBaseUrl] stringByAppendingString:@"sponsoredpage/list-json"];
[RobloxData hitEndpoint:urlAsString
isGetRequest:YES
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSMutableArray* jsonArray = responseObject;
if (jsonArray)
handler([RBXSponsoredEvent EventsWithJson:jsonArray]);
else
handler(nil);
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(nil);
}];
}
/* sendMessage: Send o reply a message to another user
*/
+ (void) sendMessage:(NSString*)body
subject:(NSString*)subject
recipientID:(NSNumber*)recipientID
replyMessageID:(NSNumber*)replyMessageID
completion:(void(^)(BOOL success, NSString* errorMessage))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@messages/send", [RobloxInfo getBaseUrl]];
NSMutableDictionary* message = [NSMutableDictionary dictionary];
[message setObject:subject forKey:@"subject"];
[message setObject:body forKey:@"body"];
[message setObject:recipientID forKey:@"recipientId"];
if(replyMessageID != nil)
[message setObject:replyMessageID forKey:@"replyMessageId"];
RobloxXSRFRequest* request = [[RobloxXSRFRequest alloc] initWithBaseURL:nil];
request.requestSerializer = [AFJSONRequestSerializer serializer];
[request XSRFPOST:urlAsString parameters:message
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
if(responseObject != nil)
{
BOOL success = [responseObject unsignedValueForKey:@"success"] != 0;
if(success)
handler(YES, nil);
else
handler(NO, [responseObject stringForKey:@"message"]);
}
else
{
handler(NO, NSLocalizedString(@"UnknownError", nil));
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO, NSLocalizedString(@"UnknownError", nil));
}];
}
/* archiveMessage: Sends a message to the archived folder
*/
+ (void) archiveMessage:(NSUInteger)messageID
completion:(void(^)(BOOL success))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@messages/api/archive-messages?messageIds[0]=%lu",
[RobloxInfo getBaseUrl],
(unsigned long)messageID];
[self hitEndpoint:urlAsString
isGetRequest:NO
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
//the response object is an array of failed archived messages, a zero count array means success
NSArray* response = responseObject;
handler(response && response.count == 0);
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(false);
}];
}
/* unarchiveMessage: Removes a message from the archived folder
*/
+ (void) unarchiveMessage:(NSUInteger)messageID
completion:(void(^)(BOOL success))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@messages/api/unarchive-messages?messageIds[0]=%lu",
[RobloxInfo getBaseUrl],
(unsigned long)messageID];
[self hitEndpoint:urlAsString
isGetRequest:NO
handleSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
//the response object is an array of failed archived messages, a zero count array means success
NSArray* response = responseObject;
handler(response && response.count == 0);
}
handleFailure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(false);
}];
}
/* purchaseProduct: Purchase any product by its product ID
*/
+ (void) purchaseProduct:(NSUInteger)productID
currencyType:(RBXCurrencyType)currencyType
purchasePrice:(NSUInteger)purchasePrice
completion:(void(^)(BOOL success, NSString* errorMessage))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@/marketplace/purchase-from-anywhere"
@"?productId=%lu"
@"&currencyTypeId=%lu"
@"&purchasePrice=%lu",
[RobloxInfo getApiBaseUrl],
(unsigned long)productID,
(unsigned long)currencyType,
(unsigned long)purchasePrice];
RobloxXSRFRequest* request = [[RobloxXSRFRequest alloc] initWithBaseURL:nil];
request.requestSerializer = [AFJSONRequestSerializer serializer];
[request XSRFPOST:urlAsString parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
if(responseObject != nil)
{
BOOL success = [responseObject unsignedValueForKey:@"success"] != 0;
if(success)
handler(YES, nil);
else
handler(NO, [responseObject stringForKey:@"message"]);
}
else
{
handler(NO, NSLocalizedString(@"UnknownError", nil));
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO, NSLocalizedString(@"UnknownError", nil));
}];
}
/* voteForAssetID: Vote for item
*/
+ (void) voteForAssetID:(NSString*)assetID
votePositive:(BOOL)votePositive
completion:(void(^)(BOOL success, NSString* message, NSUInteger totalPositives, NSUInteger totalNegatives, RBXUserVote userVote))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@/voting/vote?assetId=%@&vote=%@",
[RobloxInfo getBaseUrl],
assetID,
votePositive ? @"true" : @"false"];
RobloxXSRFRequest* request = [[RobloxXSRFRequest alloc] initWithBaseURL:nil];
request.requestSerializer = [AFJSONRequestSerializer serializer];
[request XSRFPOST:urlAsString parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
if(responseObject != nil)
{
BOOL success = [responseObject[@"Success"] boolValue];
if(success)
{
NSDictionary* model = [responseObject dictionaryForKey:@"Model"];
NSUInteger upVotes = [model unsignedValueForKey:@"UpVotes"];
NSUInteger downVotes = [model unsignedValueForKey:@"DownVotes"];
RBXUserVote userVote;
id responseUserVote = [model objectForKey:@"UserVote"];
if(responseUserVote != nil && [responseUserVote isKindOfClass:[NSNumber class]] )
userVote = [responseUserVote boolValue] == YES ? RBXUserVotePositive : RBXUserVoteNegative;
else
userVote = RBXUserVoteNoVote;
handler(YES, nil, upVotes, downVotes, userVote);
}
else
{
NSString* message = nil;
NSString* modalType = [responseObject stringForKey:@"ModalType"];
if( [modalType isEqualToString:@"FloodCheckThresholdMet"] )
{
message = NSLocalizedString(@"VotingTooQuicklyPhrase", nil);
}
else if( [modalType isEqualToString:@"PlayGame"] )
{
message = NSLocalizedString(@"VotingGameNotPlayed", nil);
}
if( message == nil )
{
message = [responseObject stringForKey:@"Message" withDefault:nil];
}
if( message != nil )
{
handler(NO, message, 0, 0, RBXUserVoteNoVote);
}
else
{
handler(NO, NSLocalizedString(@"UnknownError", nil), 0, 0, RBXUserVoteNoVote);
}
}
}
else
{
handler(NO, NSLocalizedString(@"UnknownError", nil), 0, 0, RBXUserVoteNoVote);
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO, NSLocalizedString(@"UnknownError", nil), 0, 0, RBXUserVoteNoVote);
}];
}
/* favoriteToggleForAssetID: Toggle favorite for item
*/
+ (void) favoriteToggleForAssetID:(NSString*)assetID
completion:(void(^)(BOOL success, NSString* message))handler
{
NSString* urlAsString = [NSString stringWithFormat:@"%@/favorite/toggle?assetId=%@",
[RobloxInfo getBaseUrl],
assetID];
RobloxXSRFRequest* request = [[RobloxXSRFRequest alloc] initWithBaseURL:nil];
request.requestSerializer = [AFJSONRequestSerializer serializer];
[request XSRFPOST:urlAsString parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
if(responseObject != nil)
{
BOOL success = [responseObject boolValueForKey:@"success"];
if(success)
handler(YES, nil);
else
{
NSString* message = [responseObject stringForKey:@"message" withDefault:nil];
if(message != nil)
handler(NO, message);
else
handler(NO, NSLocalizedString(@"UnknownError", nil));
}
}
else
{
handler(NO, NSLocalizedString(@"UnknownError", nil));
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
handler(NO, NSLocalizedString(@"UnknownError", nil));
}];
}
/* Helper Function - Hit Endpoint
*/
+ (NSData*) hitEndpointSynchronous:(NSString*)urlAsString
isGetRequest:(BOOL) isGET
response:(NSURLResponse**)response
error:(NSError **) responseError
{
//build the url
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlAsString]];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
[request setHTTPMethod:(isGET) ? @"GET" : @"POST"];
//response can be nil
return [NSURLConnection sendSynchronousRequest:request returningResponse:response error:responseError];;
}
+ (void) hitEndpoint:(NSString*)urlAsString
isGetRequest:(BOOL)isGET
handleSuccess:(void(^)(AFHTTPRequestOperation* operation, id responseObject))successfulOperation
handleFailure:(void(^)(AFHTTPRequestOperation* operation, NSError* error))failedOperation
{
//build the request object
if (isGET)
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[[NSURL alloc] initWithString:urlAsString]];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[RobloxInfo setDefaultHTTPHeadersForRequest:request];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.completionQueue = _completionQueue;
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
if (successfulOperation)
successfulOperation(operation, responseObject);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
if (failedOperation)
failedOperation(operation, error);
}];
//fire the request
NSOperationQueue* queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];
}
else
{
RobloxXSRFRequest* request = [[RobloxXSRFRequest alloc] initWithBaseURL:nil];
request.requestSerializer = [AFJSONRequestSerializer serializer];
[request XSRFPOST:urlAsString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject)
{
if (successfulOperation)
successfulOperation(operation, responseObject);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
if (failedOperation)
failedOperation(operation, error);
}];
}
}
@end