├── .gitignore ├── LICENSE.md ├── Logo.png ├── MVDribbbleKit.podspec ├── MVDribbbleKit ├── Helpers │ ├── MVConstants.h │ └── MVConstants.m ├── MVAuthBrowser.h ├── MVAuthBrowser.m ├── MVDribbbleKit.h ├── MVDribbbleKit.m └── Models │ ├── MVAttachment.h │ ├── MVAttachment.m │ ├── MVBucket.h │ ├── MVBucket.m │ ├── MVComment.h │ ├── MVComment.m │ ├── MVJob.h │ ├── MVJob.m │ ├── MVLike.h │ ├── MVLike.m │ ├── MVLikedShot.h │ ├── MVLikedShot.m │ ├── MVModel.h │ ├── MVModel.m │ ├── MVProject.h │ ├── MVProject.m │ ├── MVShot.h │ ├── MVShot.m │ ├── MVUser.h │ └── MVUser.m └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2015 Marcel Voss 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelvoss/MVDribbbleKit/4007efe9472d53a3399a06b8e6b0b5e3b062ccb4/Logo.png -------------------------------------------------------------------------------- /MVDribbbleKit.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "MVDribbbleKit" 3 | s.version = "1.0" 4 | s.summary = "A modern Objective-C wrapper for the Dribbble API." 5 | 6 | s.description = <<-DESC 7 | MVDribbbleKit is a modern, full-featured and well-documented 8 | Objective-C wrapper for the official [Dribbble API](https://dribbble.com/api). 9 | DESC 10 | 11 | s.homepage = "https://github.com/marcelvoss/MVDribbbleKit" 12 | s.license = 'MIT' 13 | s.author = { "Marcel Voss" => "marcel.voss@icloud.com" } 14 | s.social_media_url = "http://twitter.com/uimarcel" 15 | s.source = { :git => "https://github.com/marcelvoss/MVDribbbleKit.git", :tag => s.version } 16 | 17 | s.source_files = "MVDribbbleKit/**/*.{h,m}" 18 | 19 | s.ios.deployment_target = '7.0' 20 | s.osx.deployment_target = '10.9' 21 | 22 | s.dependency 'SSKeychain', '~> 1.2' 23 | s.dependency 'ISO8601DateFormatter', '~> 0.7.0' 24 | 25 | s.requires_arc = true 26 | end 27 | -------------------------------------------------------------------------------- /MVDribbbleKit/Helpers/MVConstants.h: -------------------------------------------------------------------------------- 1 | // MVConstants.h 2 | // 3 | // Copyright (c) 2014-2015 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import 24 | 25 | static const NSString *kBaseURL = @"https://dribbble.com"; 26 | static const NSString *kAPIBaseURL = @"https://api.dribbble.com/v1"; 27 | static NSString *kDribbbbleKeychainService = @"DribbbbleKeychainService"; 28 | static NSString *kDribbbleAccountName = @"DribbbleAccountName"; 29 | 30 | @interface MVConstants : NSObject 31 | 32 | @end -------------------------------------------------------------------------------- /MVDribbbleKit/Helpers/MVConstants.m: -------------------------------------------------------------------------------- 1 | // MVConstants.m 2 | // 3 | // Copyright (c) 2014-2015 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import "MVConstants.h" 24 | 25 | @implementation MVConstants 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /MVDribbbleKit/MVAuthBrowser.h: -------------------------------------------------------------------------------- 1 | // MVAuthBrowser.h 2 | // 3 | // Copyright (c) 2014-2016 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import 24 | 25 | @interface MVAuthBrowser : UIViewController 26 | 27 | @property (nonatomic) NSURL *callbackURL; 28 | @property (nonatomic, strong) void (^completionHandler)(NSURL *url, NSError *error); 29 | 30 | - (instancetype)initWithURL:(NSURL *)url; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /MVDribbbleKit/MVAuthBrowser.m: -------------------------------------------------------------------------------- 1 | // MVAuthBrowser.m 2 | // 3 | // Copyright (c) 2014-2016 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import "MVAuthBrowser.h" 24 | 25 | @interface MVAuthBrowser () 26 | { 27 | UIWebView *theWebView; 28 | UIActivityIndicatorView *activityIndicator; 29 | } 30 | 31 | @property (nonatomic, copy) NSURL *url; 32 | 33 | @end 34 | 35 | @implementation MVAuthBrowser 36 | 37 | - (instancetype)initWithURL:(NSURL *)url 38 | { 39 | self = [super init]; 40 | if (self) { 41 | _url = url; 42 | } 43 | return self; 44 | } 45 | 46 | - (void)viewDidLoad 47 | { 48 | [super viewDidLoad]; 49 | 50 | self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(closeBrowser:)]; 51 | 52 | theWebView = [[UIWebView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 53 | theWebView.delegate = self; 54 | theWebView.scalesPageToFit = YES; 55 | [theWebView loadRequest:[NSURLRequest requestWithURL:_url]]; 56 | [theWebView setAutoresizingMask:(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth)]; 57 | [self.view addSubview:theWebView]; 58 | 59 | activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 60 | activityIndicator.hidesWhenStopped = YES; 61 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:activityIndicator]; 62 | } 63 | 64 | - (void)closeBrowser:(id)sender 65 | { 66 | _completionHandler(nil, [NSError errorWithDomain:@"MVDribbbleKit" code:1 userInfo:@{NSLocalizedDescriptionKey:@"User canceled authorization"}]); 67 | [self dismissViewControllerAnimated:YES completion:nil]; 68 | } 69 | 70 | - (void)didReceiveMemoryWarning 71 | { 72 | [super didReceiveMemoryWarning]; 73 | } 74 | 75 | #pragma mark - UIWebViewDelegate 76 | 77 | - (void)webViewDidStartLoad:(UIWebView *)theWebView 78 | { 79 | [activityIndicator startAnimating]; 80 | } 81 | 82 | - (void)webViewDidFinishLoad:(UIWebView *)webView 83 | { 84 | [activityIndicator stopAnimating]; 85 | self.title = [theWebView stringByEvaluatingJavaScriptFromString:@"document.title"]; 86 | } 87 | 88 | - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error 89 | { 90 | _completionHandler(nil, error); 91 | } 92 | 93 | - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType 94 | { 95 | NSString *requestURL = [[request URL] host]; 96 | if ([requestURL isEqualToString:_callbackURL.host]) { 97 | [webView stopLoading]; 98 | _completionHandler([request URL], nil); 99 | [self dismissViewControllerAnimated:YES completion:nil]; 100 | return NO; 101 | } 102 | return YES; 103 | } 104 | 105 | @end 106 | -------------------------------------------------------------------------------- /MVDribbbleKit/MVDribbbleKit.h: -------------------------------------------------------------------------------- 1 | // MVDribbbleKit.h 2 | // 3 | // Copyright (c) 2014-2016 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import 24 | 25 | // Models 26 | #import "MVShot.h" 27 | #import "MVLike.h" 28 | #import "MVUser.h" 29 | #import "MVComment.h" 30 | #import "MVAttachment.h" 31 | #import "MVBucket.h" 32 | #import "MVProject.h" 33 | #import "MVJob.h" 34 | #import "MVLikedShot.h" 35 | 36 | // Helpers 37 | #import "MVConstants.h" 38 | #import "MVAuthBrowser.h" 39 | 40 | /** An enumeration of list types. */ 41 | typedef NS_ENUM(NSInteger, MVDribbbleList) { 42 | MVDribbbleListAnimated, 43 | MVDribbbleListDebuts, 44 | MVDribbbleListPlayoffs, 45 | MVDribbbleListRebounds, 46 | MVDribbbleListTeams, 47 | MVDribbbleListAll 48 | }; 49 | 50 | /** An enumeration of sort types. */ 51 | typedef NS_ENUM(NSInteger, MVDribbbleSort) { 52 | MVDribbbleSortPopularity, 53 | MVDribbbleSortComments, 54 | MVDribbbleSortViews, 55 | MVDribbbleSortRecent 56 | }; 57 | 58 | /** An enumeration of timeframe values. */ 59 | typedef NS_ENUM(NSInteger, MVDribbbleTimeframe) { 60 | MVDribbbleTimeframeWeek, 61 | MVDribbbleTimeframeMonth, 62 | MVDribbbleTimeframeYear, 63 | MVDribbbleTimeframeEver 64 | }; 65 | 66 | /** An enumeration of user types. */ 67 | typedef NS_ENUM(NSInteger, MVDribbbleUser) { 68 | MVDribbbleUserFollowers, 69 | MVDribbbleUserFollowing, 70 | MVDribbbleUserDraftees 71 | }; 72 | 73 | /** 74 | Success handler. 75 | @param resultsArray List of results. 76 | @param response Request response. 77 | */ 78 | typedef void (^SuccessHandler) (NSArray *resultsArray, NSHTTPURLResponse *response); 79 | 80 | /** 81 | Shot handler. 82 | @param shot MVShot model object. 83 | @param response Request response. 84 | */ 85 | typedef void (^ShotHandler) (MVShot *shot, NSHTTPURLResponse *response); 86 | 87 | /** 88 | Like handler. 89 | @param like MVLike model object. 90 | @param response Request response. 91 | */ 92 | typedef void (^LikeHandler) (MVLike *like, NSHTTPURLResponse *response); 93 | 94 | /** 95 | Project handler. 96 | @param project MVProject model object. 97 | @param response Request response. 98 | */ 99 | typedef void (^ProjectHandler) (MVProject *project, NSHTTPURLResponse *response); 100 | 101 | /** 102 | User handler. 103 | @param user MVUser model object. 104 | @param response Request response. 105 | */ 106 | typedef void (^UserHandler) (MVUser *user, NSHTTPURLResponse *response); 107 | 108 | 109 | /** 110 | * Job handler. 111 | * 112 | * @param job MVJob model with the returned information. 113 | * @param response Request response 114 | */ 115 | typedef void (^JobHandler) (MVJob *job, NSHTTPURLResponse *response); 116 | 117 | /** 118 | Bucket handler. 119 | @param bucket MVBucket model object. 120 | @param response Request response. 121 | */ 122 | typedef void (^BucketHandler) (MVBucket *bucket, NSHTTPURLResponse *response); 123 | 124 | /** 125 | Attachment handler. 126 | @param attachment MVAttachment model object. 127 | @param response Request response. 128 | */ 129 | typedef void (^AttachmentHandler) (MVAttachment *attachment, NSHTTPURLResponse *response); 130 | 131 | /** 132 | Comment handler. 133 | @param comment MVComment model object. 134 | @param response Request response. 135 | */ 136 | typedef void (^CommentHandler) (MVComment *comment, NSHTTPURLResponse *response); 137 | 138 | /** 139 | Failure handler. 140 | @param error Error. 141 | @param response Request response. 142 | */ 143 | typedef void (^FailureHandler) (NSError *error, NSHTTPURLResponse *response); 144 | 145 | /** Objective-C wrapper for the Dribbble API. See http://developer.dribbble.com/v1/ and https://github.com/marcelvoss/MVDribbbleKit for more information. */ 146 | @interface MVDribbbleKit : NSObject 147 | 148 | /** 149 | Number of items per page. 150 | */ 151 | @property (nonatomic) NSNumber *itemsPerPage; 152 | 153 | /** 154 | Dribbble API scope. By default "write", "public", "comment", and "upload" are selected. 155 | */ 156 | @property (nonatomic) NSArray *scopes; 157 | 158 | /** 159 | Application Client ID. 160 | */ 161 | @property (nonatomic, copy) NSString *clientID; 162 | 163 | /** 164 | Client secret. 165 | */ 166 | @property (nonatomic, copy) NSString *clientSecret; 167 | 168 | /** 169 | Callback URL. 170 | */ 171 | @property (nonatomic, copy) NSString *callbackURL; 172 | 173 | /** 174 | Client access token for read-only access to Dribbble's API. 175 | */ 176 | @property (nonatomic, copy) NSString *clientToken; 177 | 178 | #pragma mark - Miscellaneous 179 | 180 | /** 181 | Returns a newly initialized MVDribbbleKit instance (Singleton method). 182 | @return Instance of MVDribbbleKit. 183 | */ 184 | + (MVDribbbleKit *)sharedManager; 185 | 186 | /** 187 | Initializes a new MVDribbbleKit instance with required parameters. 188 | @param clientID Client ID. 189 | @param secretID Client Secret. 190 | @param callbackURL Callback URL. 191 | @return Instance of MVDribbbleKit. 192 | */ 193 | - (instancetype)initWithClientID:(NSString *)clientID secretID:(NSString *)secretID clientToken:(NSString *)clientToken callbackURL:(NSString *)callbackURL; 194 | 195 | #pragma mark - Authorization 196 | 197 | /** 198 | Starts the authorization process for a user. 199 | @warning The client ID, client secret and callback URL properties must be set to a valid value before starting the authorization process. 200 | @param completion Block to be executed when the authorization finishes. This block takes two arguments: the error and a Boolean that specifies if the access token is stored in the keychain. 201 | */ 202 | - (void)authorizeWithCompletion:(void (^) (NSError *error, BOOL stored))completion; 203 | 204 | /** 205 | Sets required MVDribbbleKit properties. 206 | @param clientID Client ID. 207 | @param clientSecret Client Secret. 208 | @param callbackURL Callback URL. 209 | */ 210 | - (void)setClientID:(NSString *)clientID clientSecret:(NSString *)clientSecret clientToken:(NSString *)clientToken callbackURL:(NSString *)callbackURL; 211 | 212 | /** 213 | * Searches the keychain for an access token and returns a boolean value whether a token was found or not. 214 | * 215 | * @return A boolean value if an access token is stored in the keychain. 216 | */ 217 | - (BOOL)isAuthorized; 218 | 219 | 220 | - (void)retrieveAccessToken:(void (^)(NSString *token, 221 | NSError *error))completionHandler; 222 | 223 | /** 224 | * Removes the stored access token from the keychain. 225 | */ 226 | - (void)removeAccount; 227 | 228 | #pragma mark - Users 229 | 230 | /** 231 | Get details for user. If userID is nil, return the authenticated user. 232 | @param userID ID of the user. 233 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the MVUser and the request response. 234 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 235 | */ 236 | - (void)getDetailsForUser:(NSString *)userID 237 | success:(UserHandler)success 238 | failure:(FailureHandler)failure; 239 | 240 | /** 241 | Get followers for user. 242 | @param page Results page. 243 | @param userID ID of the user. 244 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the list of results and the request response. 245 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 246 | */ 247 | - (void)getFollowersForUser:(NSString *)userID page:(NSInteger)page 248 | success:(SuccessHandler)success 249 | failure:(FailureHandler)failure; 250 | 251 | /** 252 | Get users followed by a user. 253 | @param page Results page. 254 | @param userID ID of the user. 255 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the list of results and the request response. 256 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 257 | */ 258 | - (void)getFollowingsForUser:(NSString *)userID page:(NSInteger)page 259 | success:(SuccessHandler)success 260 | failure:(FailureHandler)failure; 261 | 262 | /** 263 | Follow a user. 264 | @param userID ID of the user. 265 | @param success Block to be executed when the request finishes successfully. This block takes one argument: the request response. 266 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 267 | */ 268 | - (void)followUserWithID:(NSString *)userID 269 | success:(void (^) (NSHTTPURLResponse *response))success 270 | failure:(FailureHandler)failure; 271 | 272 | /** 273 | Unfollow a user. 274 | @param userID ID of the user. 275 | @param success Block to be executed when the request finishes successfully. This block takes one argument: the request response. 276 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 277 | */ 278 | - (void)unfollowUserWithID:(NSString *)userID 279 | success:(void (^) (NSHTTPURLResponse *response))success 280 | failure:(FailureHandler)failure; 281 | 282 | - (void)isUser:(NSString *)userID followingUser:(NSString *)targetUserID 283 | success:(void (^) (NSHTTPURLResponse *response, BOOL following))success 284 | failure:(FailureHandler)failure; 285 | 286 | #pragma mark - Teams 287 | 288 | /** 289 | Get teams for a user. If userID is nil, use the authenticated user. 290 | @param userID ID of the user. 291 | @param page Results page. 292 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the list of results and the request response. 293 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 294 | */ 295 | - (void)getTeamsForUserWithID:(NSString *)userID page:(NSInteger)page 296 | success:(SuccessHandler)success 297 | failure:(FailureHandler)failure; 298 | 299 | #pragma mark - Shots 300 | 301 | /** 302 | List shots. 303 | @param date Limit the timeframe to a specific date. 304 | @param sorting Limit results to a specific `SortType` (SortTypePopularity, SortTypeComments, SortTypeViews, SortTypeRecent). 305 | @param timeframe A period of time to limit the results (use timeframe enum). 306 | @param page Results page. 307 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the list of results and the request response. 308 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 309 | */ 310 | - (void)getShotsOnList:(MVDribbbleList)list 311 | date:(NSDate *)date 312 | sort:(MVDribbbleSort)sorting 313 | timeframe:(MVDribbbleTimeframe)timeframe 314 | page:(NSInteger)page 315 | success:(SuccessHandler)success 316 | failure:(FailureHandler)failure; 317 | 318 | /** 319 | Get a shot. 320 | @param shotID ID of the shot. 321 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the MVShot and the request response. 322 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 323 | */ 324 | - (void)getShotWithID:(NSInteger)shotID 325 | success:(ShotHandler)success 326 | failure:(FailureHandler)failure; 327 | 328 | /** 329 | Create a shot. 330 | @param title Title of the shot. 331 | @param imageData Image of the shot. 332 | @param description Description of the shot. 333 | @param tags Tags for the shot. 334 | @param teamID ID of the team to associate the shot with. 335 | @param reboundShot ID of the shot that the new shot is a rebound of. 336 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the MVShot and the request response. 337 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 338 | */ 339 | // TODO: Needs optimization 340 | - (void)createShotWithTitle:(NSString *)title image:(NSData *)imageData 341 | description:(NSString *)description tags:(NSArray *)tags team:(NSInteger)teamID reboundTo:(NSInteger)reboundShot 342 | success:(ShotHandler)success 343 | failure:(FailureHandler)failure; 344 | 345 | /** 346 | Update a shot. 347 | @param shotID ID of the shot. 348 | @param title Title of the shot. 349 | @param description Description of the shot. 350 | @param tags Tags for the shot. 351 | @param teamID ID of the team to associate the shot with. 352 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the MVShot and the request response. 353 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 354 | */ 355 | - (void)updateShotWithID:(NSInteger)shotID title:(NSString *)title 356 | description:(NSString *)description tags:(NSArray *)tags teamID:(NSInteger)teamID 357 | success:(ShotHandler)success 358 | failure:(FailureHandler)failure; 359 | 360 | /** 361 | Delete a shot. 362 | @param shotID ID of the shot. 363 | @param success Block to be executed when the request finishes successfully. This block takes one argument: the request response. 364 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 365 | */ 366 | // TODO: Debug this 367 | - (void)deleteShotWithID:(NSInteger)shotID 368 | success:(void (^) (NSHTTPURLResponse *response))success 369 | failure:(FailureHandler)failure; 370 | 371 | // TODO: Still missing 372 | 373 | 374 | /* 375 | Get shots for user. 376 | @param userID ID of the user. 377 | @param page Results page. 378 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the list of results and the request response. 379 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 380 | */ 381 | - (void)getShotsByUser:(NSString *)userID page:(NSInteger)page 382 | success:(SuccessHandler)success 383 | failure:(FailureHandler)failure; 384 | 385 | /* 386 | Get shots liked by user. 387 | @param userID ID of the user. 388 | @param page Results page. 389 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the list of results and the request response. 390 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 391 | */ 392 | - (void)getLikedShotsByUser:(NSString *)userID page:(NSInteger)page 393 | success:(SuccessHandler)success 394 | failure:(FailureHandler)failure; 395 | 396 | /** 397 | Get timeline for user. 398 | @param userID ID of the user. 399 | @param page Results page. 400 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the list of results and the request response. 401 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 402 | */ 403 | // TODO: Needs a new name 404 | - (void)getTimelineOfUser:(NSString *)userID page:(NSInteger)page 405 | success:(SuccessHandler)success 406 | failure:(FailureHandler)failure; 407 | 408 | #pragma mark - Likes 409 | 410 | /** 411 | List the likes for a shot. 412 | @param shotID ID of the shot. 413 | @param page Results page. 414 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the list of results and the request response. 415 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 416 | */ 417 | - (void)getLikesForShot:(NSInteger)shotID page:(NSInteger)page 418 | success:(SuccessHandler)success 419 | failure:(FailureHandler)failure; 420 | 421 | /** 422 | Like a shot. Liking a shot requires the user to be authenticated with the "write" scope. 423 | @param shotID ID of the shot. 424 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the MVLike and the request response. 425 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 426 | */ 427 | - (void)likeShotWithID:(NSInteger)shotID 428 | success:(LikeHandler)success 429 | failure:(FailureHandler)failure; 430 | 431 | /** 432 | Unlike a shot. Liking a shot requires the user to be authenticated with the "write" scope. 433 | @param shotID ID of the shot. 434 | @param success Block to be executed when the request finishes successfully. This block takes one argument: the request response. 435 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 436 | */ 437 | - (void)unlikeShotWithID:(NSInteger)shotID 438 | success:(void (^) (NSHTTPURLResponse *response))success 439 | failure:(FailureHandler)failure; 440 | 441 | /** 442 | Checks if the given shot is liked. 443 | @param shotID ID of the shot. 444 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the MVLike and the request response. 445 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 446 | */ 447 | - (void)isShotLiked:(NSInteger)shotID 448 | success:(LikeHandler)success 449 | failure:(FailureHandler)failure; 450 | 451 | 452 | #pragma mark - Attachments 453 | 454 | /** 455 | Get attachments for shot. 456 | @param shotID ID of the shot. 457 | @param page Results page. 458 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the list of results and the request response. 459 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 460 | */ 461 | - (void)getAttachmentsForShot:(NSInteger)shotID page:(NSInteger)page 462 | success:(SuccessHandler)success 463 | failure:(FailureHandler)failure; 464 | 465 | /** 466 | Get attachment for shot. 467 | @param attachmentID ID of the attachment 468 | @param shotID ID of the shot. 469 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the MVAttachment and the request response. 470 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 471 | */ 472 | - (void)getAttachmentWithID:(NSInteger)attachmentID onShot:(NSInteger)shotID 473 | success:(AttachmentHandler)success 474 | failure:(FailureHandler)failure; 475 | 476 | /** 477 | Create attachment for shot. 478 | @param shotID ID of the shot. 479 | @param attachmentData Image for the attachment. 480 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the MVAttachment and the request response. 481 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 482 | */ 483 | - (void)createAttachmentForShot:(NSInteger)shotID fromData:(NSData *)attachmentData 484 | success:(AttachmentHandler)success 485 | failure:(FailureHandler)failure; 486 | 487 | /** 488 | Delete attachment for shot. 489 | @param attachmentID ID of the attachment 490 | @param shotID ID of the shot. 491 | @param success Block to be executed when the request finishes successfully. This block takes one argument: the request response. 492 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 493 | */ 494 | - (void)deleteAttachmetWithID:(NSInteger)attachmentID onShot:(NSInteger)shotID 495 | success:(void (^) (NSHTTPURLResponse *response))success 496 | failure:(FailureHandler)failure; 497 | 498 | #pragma mark - Comments 499 | 500 | /** 501 | Get comments for shot. 502 | @param shotID ID of the shot. 503 | @param page Results page. 504 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the list of results and the request response. 505 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 506 | */ 507 | - (void)getCommentsForShot:(NSInteger)shotID page:(NSInteger)page 508 | success:(SuccessHandler)success 509 | failure:(FailureHandler)failure; 510 | 511 | /** 512 | Get likes for comments. 513 | @param commentID ID of the comment. 514 | @param shotID ID of the shot. 515 | @param page Results page. 516 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the list of results and the request response. 517 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 518 | */ 519 | - (void)getLikesForCommentWithID:(NSInteger)commentID onShot:(NSInteger)shotID page:(NSInteger)page 520 | success:(SuccessHandler)success 521 | failure:(FailureHandler)failure; 522 | 523 | /** 524 | Add a comment for shot. 525 | @param shotID ID of the shot. 526 | @param body Comment body. 527 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the MVComment and the request response. 528 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 529 | */ 530 | - (void)createCommentForShot:(NSInteger)shotID body:(NSString *)body 531 | success:(CommentHandler)success 532 | failure:(FailureHandler)failure; 533 | 534 | /** 535 | Get comment. 536 | @param commentID ID of the comment. 537 | @param shotID ID of the shot. 538 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the MVComment and the request response. 539 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 540 | */ 541 | - (void)getCommentWithID:(NSInteger)commentID onShot:(NSInteger)shotID 542 | success:(CommentHandler)success 543 | failure:(FailureHandler)failure; 544 | 545 | /** 546 | Update comment. 547 | @param commentID ID of the comment. 548 | @param shotID ID of the shot. 549 | @param body Comment body. 550 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the MVComment and the request response. 551 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 552 | */ 553 | // FIXME: Doesn't work 554 | - (void)updateCommentWithID:(NSInteger)commentID onShot:(NSInteger)shotID body:(NSString *)body 555 | success:(CommentHandler)success 556 | failure:(FailureHandler)failure; 557 | 558 | /** 559 | Like a comment. 560 | @param commentID ID of the comment. 561 | @param shotID ID of the shot. 562 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the MVLike and the request response. 563 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 564 | */ 565 | - (void)likeCommentWithID:(NSInteger)commentID onShot:(NSInteger)shotID 566 | success:(LikeHandler)success 567 | failure:(FailureHandler)failure; 568 | 569 | /** 570 | Unlike a comment. 571 | @param commentID ID of the comment. 572 | @param shotID ID of the shot. 573 | @param success Block to be executed when the request finishes successfully. This block takes one argument: the request response. 574 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 575 | */ 576 | - (void)unlikeCommentWithID:(NSInteger)commentID onShot:(NSInteger)shotID 577 | success:(void (^) (NSHTTPURLResponse *response))success 578 | failure:(FailureHandler)failure; 579 | 580 | /** 581 | Check if comment is liked. 582 | @param commentID ID of the comment. 583 | @param shotID ID of the shot. 584 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the MVLike and the request response. 585 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 586 | */ 587 | - (void)checkIfCommentIsLiked:(NSInteger)commentID onShot:(NSInteger)shotID 588 | success:(LikeHandler)success 589 | failure:(FailureHandler)failure; 590 | 591 | #pragma mark - Rebounds 592 | 593 | /** 594 | Get rebounds for shot. 595 | @param shotID ID of the shot. 596 | @param page Results page. 597 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the list of results and the request response. 598 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 599 | */ 600 | - (void)getReboundsForShot:(NSInteger)shotID page:(NSInteger)page 601 | success:(SuccessHandler)success 602 | failure:(FailureHandler)failure; 603 | 604 | #pragma mark - Buckets 605 | 606 | /** 607 | Get bucket. 608 | @param bucketID ID of the bucket. 609 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the MVBucket and the request response. 610 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 611 | */ 612 | - (void)getBucketWithID:(NSInteger)bucketID 613 | success:(BucketHandler)success 614 | failure:(FailureHandler)failure; 615 | 616 | /** 617 | Create bucket. 618 | @param bucketName Name of the bucket. 619 | @param bucketDescription Description of the bucket. 620 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the MVBucket and the request response. 621 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 622 | */ 623 | - (void)createBucketWithName:(NSString *)bucketName description:(NSString *)bucketDescription 624 | success:(BucketHandler)success 625 | failure:(FailureHandler)failure; 626 | 627 | /** 628 | Update bucket 629 | @param bucketID ID of the bucket. 630 | @param bucketName Name of the bucket. 631 | @param bucketDescription Description of the bucket. 632 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the MVBucket and the request response. 633 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 634 | */ 635 | - (void)updateBucketWithID:(NSInteger)bucketID name:(NSString *)bucketName description:(NSString *)bucketDescription 636 | success:(BucketHandler)success 637 | failure:(FailureHandler)failure; 638 | 639 | /** 640 | Delete bucket. 641 | @param bucketID ID of the bucket. 642 | @param success Block to be executed when the request finishes successfully. This block takes one argument: the request response. 643 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 644 | */ 645 | - (void)deleteBucketWithID:(NSInteger)bucketID 646 | success:(void (^) (NSHTTPURLResponse *response))success 647 | failure:(FailureHandler)failure; 648 | 649 | /** 650 | Get shots in bucklet. 651 | @param bucketID ID of the bucket. 652 | @param page Results page. 653 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the list of results and the request response. 654 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 655 | */ 656 | - (void)getShotsInBucket:(NSInteger)bucketID page:(NSInteger)page 657 | success:(SuccessHandler)success 658 | failure:(FailureHandler)failure; 659 | 660 | /** 661 | Add shot to bucket. 662 | @param shotID ID of the shot. 663 | @param bucketID ID of the bucket. 664 | @param success Block to be executed when the request finishes successfully. This block takes one argument: the request response. 665 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 666 | */ 667 | - (void)addShotToBucket:(NSInteger)shotID bucket:(NSInteger)bucketID 668 | success:(void (^) (NSHTTPURLResponse *response))success 669 | failure:(FailureHandler)failure; 670 | 671 | /** 672 | Remove shot from bucket. 673 | @param shotID ID of the shot. 674 | @param bucketID ID of the bucket. 675 | @param success Block to be executed when the request finishes successfully. This block takes one argument: the request response. 676 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 677 | */ 678 | - (void)removeShotFromBucket:(NSInteger)shotID bucket:(NSInteger)bucketID 679 | success:(void (^) (NSHTTPURLResponse *response))success 680 | failure:(FailureHandler)failure; 681 | 682 | #pragma mark - Projects 683 | 684 | /** 685 | Get project. 686 | @param projectID ID of the project. 687 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the MVProject and the request response. 688 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 689 | */ 690 | - (void)getProjectWithID:(NSInteger)projectID 691 | success:(ProjectHandler)success 692 | failure:(FailureHandler)failure; 693 | 694 | /** 695 | Get shots in project. 696 | @param projectID ID of the project. 697 | @param success Block to be executed when the request finishes successfully. This block takes two arguments: the list of results and the request response. 698 | @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 699 | */ 700 | - (void)getShotsInProject:(NSInteger)projectID 701 | success:(SuccessHandler)success 702 | failure:(FailureHandler)failure; 703 | 704 | 705 | /** 706 | * Post a new job to Dribbble's jobs dashboard. 707 | * 708 | * @param organizationName The name of the company, offering this job 709 | * @param jobTitle Title of the job position 710 | * @param jobLocation Location of the job 711 | * @param jobDetails A URL leading to the full job lisiting 712 | * @param jobActive If YES, the job listing will be immediately published 713 | * @param success Block to be executed when the request finishes successfully. This block takes two arguments: the job result and the request response. 714 | * @param failure Block to be executed when the request finishes unsuccessfully. This block takes two arguments: the error and the request response. 715 | * 716 | * @note In order to access this endpoint, you require a special access key. Contact Dribbble for more information. 717 | */ 718 | - (void)createJobInOrganization:(NSString *)organizationName 719 | jobPosition:(NSString *)jobTitle 720 | location:(NSString *)jobLocation 721 | detailURL:(NSString *)jobDetails 722 | active:(BOOL)jobActive 723 | success:(JobHandler)success 724 | failure:(FailureHandler)failure; 725 | 726 | @end 727 | -------------------------------------------------------------------------------- /MVDribbbleKit/MVDribbbleKit.m: -------------------------------------------------------------------------------- 1 | // MVDribbbleKit.m 2 | // 3 | // Copyright (c) 2014-2016 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import "MVDribbbleKit.h" 24 | 25 | #import 26 | 27 | @interface MVDribbbleKit (Private) 28 | 29 | // Retrieve access token from keychain 30 | - (NSString *)retrieveToken; 31 | 32 | // Used for retrieving resources. 33 | - (void)GETOperationWithURL:(NSString *)url parameters:(NSDictionary *)parameters 34 | success:(void (^) (NSDictionary *results, NSHTTPURLResponse *response))success 35 | failure:(void (^) (NSError *error, NSHTTPURLResponse *response))failure; 36 | 37 | // Used for updating resources, or performing custom actions. 38 | - (void)PUTOperationWithURL:(NSString *)url parameters:(NSDictionary *)parameters 39 | success:(void (^) (NSDictionary *results, NSHTTPURLResponse *response))success 40 | failure:(void (^) (NSError *error, NSHTTPURLResponse *response))failure; 41 | 42 | // Used for creating resources. 43 | - (void)POSTOperationWithURL:(NSString *)url parameters:(NSDictionary *)parameters 44 | success:(void (^) (NSDictionary *results, NSHTTPURLResponse *response))success 45 | failure:(void (^) (NSError *error, NSHTTPURLResponse *response))failure; 46 | 47 | // Used for deleting resources. 48 | - (void)DELETEOperationWithURL:(NSString *)url parameters:(NSDictionary *)parameters 49 | success:(void (^) (NSHTTPURLResponse *response))success 50 | failure:(void (^) (NSError *error, NSHTTPURLResponse *response))failure; 51 | 52 | @end 53 | 54 | @implementation MVDribbbleKit 55 | 56 | #pragma mark - Miscellaneous 57 | 58 | - (instancetype)initWithClientID:(NSString *)clientID secretID:(NSString *)secretID clientToken:(NSString *)clientToken callbackURL:(NSString *)callbackURL 59 | { 60 | self = [super init]; 61 | if (self) { 62 | _clientID = clientID; 63 | _clientSecret = secretID; 64 | _callbackURL = callbackURL; 65 | _clientToken = clientToken; 66 | } 67 | return self; 68 | } 69 | 70 | + (MVDribbbleKit *)sharedManager 71 | { 72 | static MVDribbbleKit *instance; 73 | static dispatch_once_t onceToken; 74 | dispatch_once(&onceToken, ^{ 75 | instance = [MVDribbbleKit new]; 76 | instance.itemsPerPage = @30; 77 | }); 78 | return instance; 79 | } 80 | 81 | #pragma mark - Authorization 82 | 83 | - (void)authorizeWithCompletion:(void (^)(NSError *, BOOL))completion 84 | { 85 | // GET /oauth/authorize 86 | // GET https://dribbble.com/oauth/authorize 87 | 88 | NSMutableString *urlString; 89 | 90 | // Create a scopes string 91 | if (_scopes == nil) { 92 | 93 | // If the _scopes array is empty, it'll automatically use all four scopes 94 | urlString = [NSMutableString stringWithFormat:@"%@/oauth/authorize?client_id=%@&scope=write+upload+public+comment", kBaseURL, _clientID]; 95 | 96 | } else { 97 | NSMutableString *tempString = [NSMutableString stringWithFormat:@"%@/oauth/authorize?client_id=%@&scope=", kBaseURL, _clientID]; 98 | 99 | for (NSString *scope in _scopes) { 100 | if (_scopes.lastObject == scope) { 101 | [tempString appendString:scope]; 102 | } else { 103 | NSString *string = [NSString stringWithFormat:@"%@+", scope]; 104 | [tempString appendString:string]; 105 | } 106 | 107 | } 108 | urlString = tempString; 109 | } 110 | 111 | NSURL *url = [NSURL URLWithString:urlString]; 112 | 113 | UIWindow *window = [[[UIApplication sharedApplication] delegate] window]; 114 | UIViewController *controller = window.rootViewController; 115 | 116 | MVAuthBrowser *authBrowser = [[MVAuthBrowser alloc] initWithURL:url]; 117 | authBrowser.callbackURL = [NSURL URLWithString:_callbackURL]; 118 | UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:authBrowser]; 119 | 120 | [controller presentViewController:navController animated:YES completion:nil]; 121 | 122 | authBrowser.completionHandler = ^(NSURL *url, NSError *error) { 123 | if (error == nil) { 124 | // POST /oauth/token 125 | // https://dribbble.com/oauth/token 126 | 127 | NSString *urlString = [NSString stringWithFormat:@"%@/oauth/token", kBaseURL]; 128 | 129 | // Extract the temporary code 130 | NSString *codeString = [[url query] stringByReplacingOccurrencesOfString:@"code=" withString:@""]; 131 | 132 | // Exchange the temporary code for an access token 133 | [self POSTOperationWithURL:urlString parameters:@{@"client_id": _clientID, @"client_secret": _clientSecret, @"code": codeString} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 134 | 135 | NSString *accessToken = results[@"access_token"]; 136 | 137 | NSError *keychainError = nil; 138 | [SSKeychain setPassword:accessToken forService:kDribbbbleKeychainService 139 | account:kDribbbleAccountName error:&keychainError]; 140 | 141 | if (keychainError) { 142 | completion(nil, NO); 143 | } else { 144 | completion(nil, YES); 145 | } 146 | 147 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 148 | completion(error, NO); 149 | }]; 150 | } else { 151 | completion(error, NO); 152 | } 153 | }; 154 | } 155 | 156 | - (void)setClientID:(NSString *)clientID clientSecret:(NSString *)clientSecret clientToken:(NSString *)clientToken callbackURL:(NSString *)callbackURL 157 | { 158 | _clientID = clientID; 159 | _clientSecret = clientSecret; 160 | _callbackURL = callbackURL; 161 | _clientToken = clientToken; 162 | } 163 | 164 | - (BOOL)isAuthorized 165 | { 166 | if ([SSKeychain accountsForService:kDribbbbleKeychainService]) { 167 | return YES; 168 | } else { 169 | return NO; 170 | } 171 | } 172 | 173 | - (void)removeAccount 174 | { 175 | if ([SSKeychain accountsForService:kDribbbbleKeychainService]) { 176 | NSString *accountUsername = [[SSKeychain accountsForService:kDribbbbleKeychainService][0] 177 | valueForKey:kSSKeychainAccountKey]; 178 | 179 | NSError *deletionError = nil; 180 | [SSKeychain deletePasswordForService:kDribbbbleKeychainService account:accountUsername 181 | error:&deletionError]; 182 | 183 | if (deletionError) { 184 | NSLog(@"Couldn't delete token"); 185 | } 186 | } 187 | } 188 | 189 | - (void)retrieveAccessToken:(void (^)(NSString *, NSError *))completionHandler 190 | { 191 | if ([SSKeychain accountsForService:kDribbbbleKeychainService]) { 192 | NSString *accountUsername = [[SSKeychain accountsForService:kDribbbbleKeychainService][0] 193 | valueForKey:kSSKeychainAccountKey]; 194 | 195 | NSError *keychainError = nil; 196 | NSString *accessToken = [SSKeychain passwordForService:kDribbbbleKeychainService account:accountUsername error:&keychainError]; 197 | 198 | completionHandler([SSKeychain passwordForService:kDribbbbleKeychainService 199 | account:accessToken], keychainError); 200 | } else if (_clientToken != nil) { 201 | completionHandler(_clientToken, nil); 202 | } else { 203 | completionHandler(nil, [NSError errorWithDomain:@"com.marcelvoss.MVDribbbleKit" code:1 userInfo:@{NSLocalizedDescriptionKey: @"Couldn't find a stored Dribbble account in keychain."}]); 204 | } 205 | } 206 | 207 | #pragma mark - Users 208 | 209 | - (void)isUser:(NSString *)userID followingUser:(NSString *)targetUserID 210 | success:(void (^)(NSHTTPURLResponse *, BOOL))success 211 | failure:(FailureHandler)failure 212 | { 213 | if (userID) { 214 | // GET /users/:user/following/:target_user 215 | 216 | NSString *urlString = [NSString stringWithFormat:@"%@/user/%@/following/%@", kBaseURL, userID, targetUserID]; 217 | 218 | [self GETOperationWithURL:urlString parameters:@{} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 219 | 220 | if (response.statusCode == 204) { 221 | success(response, YES); 222 | } else { 223 | success(response, NO); 224 | } 225 | 226 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 227 | failure(error, response); 228 | }]; 229 | } else { 230 | // GET /user/following/:user 231 | 232 | NSString *urlString = [NSString stringWithFormat:@"%@/user/following/%@", kBaseURL, targetUserID]; 233 | 234 | [self GETOperationWithURL:urlString parameters:@{} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 235 | 236 | if (response.statusCode == 204) { 237 | success(response, YES); 238 | } else { 239 | success(response, NO); 240 | } 241 | 242 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 243 | failure(error, response); 244 | }]; 245 | } 246 | } 247 | 248 | - (void)getDetailsForUser:(NSString *)userID 249 | success:(void (^)(MVUser *, NSHTTPURLResponse *))success 250 | failure:(FailureHandler)failure 251 | { 252 | if (userID == nil) { 253 | // Get details for the authorized player 254 | // GET /user 255 | 256 | [self GETOperationWithURL:[NSString stringWithFormat:@"%@/user", kAPIBaseURL] parameters:@{} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 257 | 258 | MVUser *user = [[MVUser alloc] initWithDictionary:results]; 259 | success(user, response); 260 | 261 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 262 | failure(error, response); 263 | }]; 264 | 265 | } else { 266 | // Get details for the specified player 267 | // GET /users/:user 268 | 269 | [self GETOperationWithURL:[NSString stringWithFormat:@"%@/users/%@", kAPIBaseURL, userID] parameters:@{} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 270 | 271 | MVUser *user = [[MVUser alloc] initWithDictionary:results]; 272 | success(user, response); 273 | 274 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 275 | failure(error, response); 276 | }]; 277 | } 278 | } 279 | 280 | - (void)getFollowersForUser:(NSString *)userID page:(NSInteger)page 281 | success:(SuccessHandler)success 282 | failure:(FailureHandler)failure 283 | { 284 | if (userID == nil) { 285 | // List the authenticated user's followers: 286 | // GET /user/followers 287 | 288 | NSString *urlString = [NSString stringWithFormat:@"%@/user/followers", kAPIBaseURL]; 289 | 290 | [self GETOperationWithURL:urlString parameters:@{@"page": [NSNumber numberWithInteger:page]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 291 | 292 | NSMutableArray *parsedResultsArray = [NSMutableArray array]; 293 | 294 | for (NSDictionary *userDictionary in results) { 295 | MVUser *user = [[MVUser alloc] initWithDictionary:userDictionary]; 296 | [parsedResultsArray addObject:user]; 297 | } 298 | 299 | success(parsedResultsArray, response); 300 | 301 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 302 | failure(error, response); 303 | }]; 304 | 305 | } else { 306 | // List a user's followers: 307 | // GET /users/:user/followers 308 | 309 | NSString *urlString = [NSString stringWithFormat:@"%@/users/%@/followers", kAPIBaseURL, userID]; 310 | 311 | [self GETOperationWithURL:urlString parameters:@{@"page": [NSNumber numberWithInteger:page]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 312 | 313 | NSMutableArray *parsedResultsArray = [NSMutableArray array]; 314 | 315 | for (NSDictionary *userDictionary in results) { 316 | MVUser *user = [[MVUser alloc] initWithDictionary:userDictionary]; 317 | [parsedResultsArray addObject:user]; 318 | } 319 | 320 | success(parsedResultsArray, response); 321 | 322 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 323 | failure(error, response); 324 | }]; 325 | } 326 | } 327 | 328 | - (void)getFollowingsForUser:(NSString *)userID page:(NSInteger)page 329 | success:(SuccessHandler)success 330 | failure:(FailureHandler)failure 331 | { 332 | if (userID == nil) { 333 | // List who the authenticated user is following: 334 | // GET /user/following 335 | 336 | NSString *urlString = [NSString stringWithFormat:@"%@/users/following", kAPIBaseURL]; 337 | 338 | [self GETOperationWithURL:urlString parameters:@{@"page": [NSNumber numberWithInteger:page]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 339 | 340 | NSMutableArray *parsedResultsArray = [NSMutableArray array]; 341 | 342 | for (NSDictionary *userDictionary in results) { 343 | MVUser *user = [[MVUser alloc] initWithDictionary:userDictionary]; 344 | [parsedResultsArray addObject:user]; 345 | } 346 | 347 | success(parsedResultsArray, response); 348 | 349 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 350 | failure(error, response); 351 | }]; 352 | 353 | 354 | } else { 355 | // List who a user is following: 356 | // GET /users/:user/following 357 | 358 | NSString *urlString = [NSString stringWithFormat:@"%@/users/%@/following", kAPIBaseURL, userID]; 359 | 360 | [self GETOperationWithURL:urlString parameters:@{@"page": [NSNumber numberWithInteger:page]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 361 | 362 | NSMutableArray *parsedResultsArray = [NSMutableArray array]; 363 | 364 | for (NSDictionary *userDictionary in results) { 365 | MVUser *user = [[MVUser alloc] initWithDictionary:userDictionary]; 366 | [parsedResultsArray addObject:user]; 367 | } 368 | 369 | success(parsedResultsArray, response); 370 | 371 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 372 | failure(error, response); 373 | }]; 374 | 375 | } 376 | } 377 | 378 | 379 | - (void)followUserWithID:(NSString *)userID 380 | success:(void (^)(NSHTTPURLResponse *))success 381 | failure:(FailureHandler)failure 382 | { 383 | // Follow a user 384 | // PUT /users/:user/follow 385 | 386 | NSString *urlString = [NSString stringWithFormat:@"%@/users/%@/follow", kAPIBaseURL, userID]; 387 | 388 | [self PUTOperationWithURL:urlString parameters:nil success:^(NSDictionary *results, NSHTTPURLResponse *response) { 389 | 390 | NSLog(@"%@ %@", results, response); 391 | success(response); 392 | 393 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 394 | failure(error, response); 395 | }]; 396 | } 397 | 398 | - (void)unfollowUserWithID:(NSString *)userID 399 | success:(void (^)(NSHTTPURLResponse *))success 400 | failure:(FailureHandler)failure 401 | { 402 | // Unfollow a user 403 | // DELETE /users/:user/follow 404 | 405 | NSString *urlString = [NSString stringWithFormat:@"%@/users/%@/follow", kAPIBaseURL, userID]; 406 | 407 | [self DELETEOperationWithURL:urlString parameters:nil success:^(NSHTTPURLResponse *response) { 408 | 409 | success(response); 410 | 411 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 412 | failure(error, response); 413 | }]; 414 | } 415 | 416 | 417 | #pragma mark - Teams 418 | 419 | - (void)getTeamsForUserWithID:(NSString *)userID page:(NSInteger)page 420 | success:(SuccessHandler)success 421 | failure:(FailureHandler)failure 422 | { 423 | if (userID == nil) { 424 | // List the authenticated user's teams: 425 | // GET /user/teams 426 | 427 | NSString *urlString = [NSString stringWithFormat:@"%@/user/teams", kAPIBaseURL]; 428 | 429 | [self GETOperationWithURL:urlString parameters:@{@"page": [NSNumber numberWithInteger:page]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 430 | 431 | NSMutableArray *parsedResultsArray = [NSMutableArray array]; 432 | 433 | for (NSDictionary *userDictionary in results) { 434 | MVUser *user = [[MVUser alloc] initWithDictionary:userDictionary]; 435 | [parsedResultsArray addObject:user]; 436 | } 437 | 438 | success(parsedResultsArray, response); 439 | 440 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 441 | failure(error, response); 442 | }]; 443 | 444 | } else { 445 | // List a user's teams: 446 | // GET /users/:user/teams 447 | 448 | NSString *urlString = [NSString stringWithFormat:@"%@/users/%@/teams", kAPIBaseURL, userID]; 449 | 450 | [self GETOperationWithURL:urlString parameters:@{@"page": [NSNumber numberWithInteger:page]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 451 | 452 | NSMutableArray *parsedResultsArray = [NSMutableArray array]; 453 | 454 | for (NSDictionary *userDictionary in results) { 455 | MVUser *user = [[MVUser alloc] initWithDictionary:userDictionary]; 456 | [parsedResultsArray addObject:user]; 457 | } 458 | 459 | success(parsedResultsArray, response); 460 | 461 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 462 | failure(error, response); 463 | }]; 464 | 465 | } 466 | } 467 | 468 | #pragma mark - Shots 469 | 470 | - (void)getShotsOnList:(MVDribbbleList)list 471 | date:(NSDate *)date 472 | sort:(MVDribbbleSort)sorting 473 | timeframe:(MVDribbbleTimeframe)timeframe 474 | page:(NSInteger)page 475 | success:(SuccessHandler)success 476 | failure:(FailureHandler)failure 477 | { 478 | // List shots 479 | // GET /shots 480 | 481 | NSString *urlString = [NSString stringWithFormat:@"%@/shots", kAPIBaseURL]; 482 | 483 | NSString *listString; 484 | switch (list) { 485 | case MVDribbbleListAnimated: 486 | listString = @"animated"; 487 | break; 488 | case MVDribbbleListDebuts: 489 | listString = @"debuts"; 490 | break; 491 | case MVDribbbleListPlayoffs: 492 | listString = @"playoffs"; 493 | break; 494 | case MVDribbbleListRebounds: 495 | listString = @"rebounds"; 496 | break; 497 | case MVDribbbleListTeams: 498 | listString = @"teams"; 499 | break; 500 | case MVDribbbleListAll: 501 | listString = @"all"; 502 | break; 503 | default: 504 | listString = @"all"; 505 | break; 506 | } 507 | 508 | NSString *sortingString; 509 | switch (sorting) { 510 | case MVDribbbleSortPopularity: 511 | sortingString = @"popularity"; 512 | break; 513 | case MVDribbbleSortComments: 514 | sortingString = @"comments"; 515 | break; 516 | case MVDribbbleSortViews: 517 | sortingString = @"views"; 518 | break; 519 | case MVDribbbleSortRecent: 520 | sortingString = @"recent"; 521 | break; 522 | default: 523 | sortingString = @"popularity"; 524 | break; 525 | } 526 | 527 | NSString *timeframeString; 528 | switch (timeframe) { 529 | case MVDribbbleTimeframeWeek: 530 | timeframeString = @"week"; 531 | break; 532 | case MVDribbbleTimeframeMonth: 533 | timeframeString = @"month"; 534 | break; 535 | case MVDribbbleTimeframeYear: 536 | timeframeString = @"year"; 537 | break; 538 | case MVDribbbleTimeframeEver: 539 | timeframeString = @"ever"; 540 | break; 541 | default: 542 | timeframeString = nil; 543 | break; 544 | } 545 | 546 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 547 | formatter.dateFormat = @"yyyy-MM-dd"; 548 | 549 | [self GETOperationWithURL:urlString parameters:@{@"list": listString, @"sort": sortingString, @"page": [NSNumber numberWithInteger:page], @"timeframe": timeframeString} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 550 | 551 | NSMutableArray *parsedResultsArray = [NSMutableArray array]; 552 | for (NSDictionary *dictionary in results) { 553 | 554 | MVShot *shot = [[MVShot alloc] initWithDictionary:dictionary]; 555 | [parsedResultsArray addObject:shot]; 556 | 557 | } 558 | success(parsedResultsArray, response); 559 | 560 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 561 | failure(error, response); 562 | }]; 563 | } 564 | 565 | - (void)getShotWithID:(NSInteger)shotID 566 | success:(void (^)(MVShot *, NSHTTPURLResponse *))success 567 | failure:(FailureHandler)failure 568 | { 569 | // Get a shot 570 | // GET /shots/:id 571 | 572 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%@", kAPIBaseURL, @(shotID)]; 573 | 574 | [self GETOperationWithURL:urlString parameters:nil success:^(NSDictionary *results, NSHTTPURLResponse *response) { 575 | 576 | MVShot *shot = [[MVShot alloc] initWithDictionary:results]; 577 | success(shot, response); 578 | 579 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 580 | failure(error, response); 581 | }]; 582 | } 583 | 584 | // Should be done 585 | // Can't really test it 586 | - (void)createShotWithTitle:(NSString *)title image:(NSData *)imageData description:(NSString *)description 587 | tags:(NSArray *)tags team:(NSInteger)teamID reboundTo:(NSInteger)reboundShot 588 | success:(void (^)(MVShot *, NSHTTPURLResponse *))success 589 | failure:(FailureHandler)failure 590 | { 591 | // Create a shot 592 | // POST /shots 593 | 594 | NSString *urlString = [NSString stringWithFormat:@"%@/shots", kAPIBaseURL]; 595 | 596 | [self POSTOperationWithURL:urlString parameters:@{@"title": title, @"description": description, @"tags": tags, @"image": imageData, @"team_id": [NSNumber numberWithInteger:teamID], @"rebound_source_id": [NSNumber numberWithInteger:reboundShot]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 597 | 598 | MVShot *shot = [[MVShot alloc] initWithDictionary:results]; 599 | success(shot, response); 600 | 601 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 602 | failure(error, response); 603 | }]; 604 | } 605 | 606 | // Should be done 607 | // Can't really test it 608 | - (void)updateShotWithID:(NSInteger)shotID title:(NSString *)title description:(NSString *)description 609 | tags:(NSArray *)tags teamID:(NSInteger)teamID 610 | success:(void (^)(MVShot *, NSHTTPURLResponse *))success 611 | failure:(FailureHandler)failure 612 | { 613 | // Update a shot 614 | // PUT /shots/:id 615 | 616 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%ld", kAPIBaseURL, (long)shotID]; 617 | 618 | [self PUTOperationWithURL:urlString parameters:@{@"title": title, @"description": description, @"tags": tags, @"team_id": [NSNumber numberWithInteger:teamID]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 619 | 620 | MVShot *shot = [[MVShot alloc] initWithDictionary:results]; 621 | success(shot, response); 622 | 623 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 624 | failure(error, response); 625 | }]; 626 | } 627 | 628 | - (void)deleteShotWithID:(NSInteger)shotID 629 | success:(void (^)(NSHTTPURLResponse *))success 630 | failure:(FailureHandler)failure 631 | { 632 | // Delete a shot 633 | // DELETE /shots/:id 634 | 635 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%@", kAPIBaseURL, @(shotID)]; 636 | 637 | [self DELETEOperationWithURL:urlString parameters:nil success:^(NSHTTPURLResponse *response) { 638 | 639 | success(response); 640 | 641 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 642 | failure(error, response); 643 | }]; 644 | } 645 | 646 | - (void)getShotsByUser:(NSString *)userID page:(NSInteger)page 647 | success:(SuccessHandler)success 648 | failure:(FailureHandler)failure 649 | { 650 | // List shots for a user 651 | 652 | if (userID == nil) { 653 | // GET /user/shots 654 | 655 | NSString *urlString = [NSString stringWithFormat:@"%@/users/shots", kAPIBaseURL]; 656 | 657 | [self GETOperationWithURL:urlString parameters:@{@"page": [NSNumber numberWithInteger:page]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 658 | 659 | NSMutableArray *parsedResultsArray = [NSMutableArray array]; 660 | for (NSDictionary *dictionary in results) { 661 | MVShot *shot = [[MVShot alloc] initWithDictionary:dictionary]; 662 | [parsedResultsArray addObject:shot]; 663 | } 664 | 665 | success(parsedResultsArray, response); 666 | 667 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 668 | failure(error, response); 669 | }]; 670 | } else { 671 | // GET /users/:user/shots 672 | 673 | NSString *urlString = [NSString stringWithFormat:@"%@/users/%@/shots", kAPIBaseURL, userID]; 674 | 675 | [self GETOperationWithURL:urlString parameters:@{@"page": [NSNumber numberWithInteger:page]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 676 | 677 | NSMutableArray *parsedResultsArray = [NSMutableArray array]; 678 | for (NSDictionary *dictionary in results) { 679 | MVShot *shot = [[MVShot alloc] initWithDictionary:dictionary]; 680 | [parsedResultsArray addObject:shot]; 681 | } 682 | 683 | success(parsedResultsArray, response); 684 | 685 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 686 | failure(error, response); 687 | }]; 688 | } 689 | } 690 | 691 | - (void)getLikedShotsByUser:(NSString *)userID page:(NSInteger)page 692 | success:(SuccessHandler)success 693 | failure:(FailureHandler)failure 694 | { 695 | // List shot likes for a user 696 | 697 | if (userID == nil) { 698 | // GET /user/likes 699 | 700 | NSString *urlString = [NSString stringWithFormat:@"%@/user/likes", kAPIBaseURL]; 701 | 702 | [self GETOperationWithURL:urlString parameters:@{@"page": [NSNumber numberWithInteger:page]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 703 | 704 | NSLog(@"%@", results); 705 | 706 | NSMutableArray *parsedResultsArray = [NSMutableArray array]; 707 | for (NSDictionary *dictionary in results) { 708 | MVLikedShot *shot = [[MVLikedShot alloc] initWithDictionary:dictionary]; 709 | [parsedResultsArray addObject:shot]; 710 | } 711 | 712 | success(parsedResultsArray, response); 713 | 714 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 715 | failure(error, response); 716 | }]; 717 | 718 | } else { 719 | // GET /users/:user/likes 720 | 721 | NSString *urlString = [NSString stringWithFormat:@"%@/user/%@/likes", kAPIBaseURL, userID]; 722 | 723 | [self GETOperationWithURL:urlString parameters:@{@"page": [NSNumber numberWithInteger:page]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 724 | 725 | NSMutableArray *parsedResultsArray = [NSMutableArray array]; 726 | for (NSDictionary *dictionary in results) { 727 | MVLikedShot *shot = [[MVLikedShot alloc] initWithDictionary:dictionary]; 728 | [parsedResultsArray addObject:shot]; 729 | } 730 | 731 | success(parsedResultsArray, response); 732 | 733 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 734 | failure(error, response); 735 | }]; 736 | } 737 | } 738 | 739 | - (void)getTimelineOfUser:(NSString *)userID page:(NSInteger)page 740 | success:(SuccessHandler)success 741 | failure:(FailureHandler)failure 742 | { 743 | // GET /user/following/shots 744 | 745 | NSString *urlString = [NSString stringWithFormat:@"%@/user/following/shots", kAPIBaseURL]; 746 | 747 | [self GETOperationWithURL:urlString parameters:@{@"page": [NSNumber numberWithInteger:page]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 748 | 749 | NSMutableArray *parsedResultsArray = [NSMutableArray array]; 750 | for (NSDictionary *dictionary in results) { 751 | MVShot *shot = [[MVShot alloc] initWithDictionary:dictionary]; 752 | [parsedResultsArray addObject:shot]; 753 | } 754 | 755 | success(parsedResultsArray, response); 756 | 757 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 758 | failure(error, response); 759 | }]; 760 | 761 | } 762 | 763 | - (void)getLikesForShot:(NSInteger)shotID page:(NSInteger)page 764 | success:(SuccessHandler)success 765 | failure:(FailureHandler)failure 766 | { 767 | // List the likes for a shot 768 | // GET /shots/:id/likes 769 | 770 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%@/likes", kAPIBaseURL, @(shotID)]; 771 | 772 | [self GETOperationWithURL:urlString parameters:@{@"page": [NSNumber numberWithInteger:page]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 773 | 774 | NSMutableArray *likesArray = [NSMutableArray array]; 775 | for (NSDictionary *dictionary in results) { 776 | MVLike *like = [[MVLike alloc] initWithDictionary:dictionary]; 777 | [likesArray addObject:like]; 778 | } 779 | 780 | success(likesArray, response); 781 | 782 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 783 | failure(error, response); 784 | }]; 785 | } 786 | 787 | - (void)likeShotWithID:(NSInteger)shotID 788 | success:(void (^)(MVLike *, NSHTTPURLResponse *))success 789 | failure:(FailureHandler)failure 790 | { 791 | // Like a shot 792 | // POST /shots/:id/like 793 | 794 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%@/like", kAPIBaseURL, @(shotID)]; 795 | 796 | [self POSTOperationWithURL:urlString parameters:@{@"id": [NSNumber numberWithInteger:shotID]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 797 | 798 | MVLike *like = [[MVLike alloc] initWithDictionary:results]; 799 | success(like, response); 800 | 801 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 802 | failure(error, response); 803 | }]; 804 | } 805 | 806 | - (void)unlikeShotWithID:(NSInteger)shotID 807 | success:(void (^)(NSHTTPURLResponse *))success 808 | failure:(FailureHandler)failure 809 | { 810 | // Unlike a shot 811 | // DELETE /shots/:id/like 812 | 813 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%@/like", kAPIBaseURL, @(shotID)]; 814 | 815 | [self DELETEOperationWithURL:urlString parameters:nil success:^(NSHTTPURLResponse *response) { 816 | 817 | success(response); 818 | 819 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 820 | failure(error, response); 821 | }]; 822 | } 823 | 824 | - (void)isShotLiked:(NSInteger)shotID 825 | success:(LikeHandler)success 826 | failure:(FailureHandler)failure 827 | { 828 | // Check if you like a shot 829 | // GET /shots/:id/like 830 | 831 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%ld/like", kAPIBaseURL, shotID]; 832 | 833 | [self GETOperationWithURL:urlString parameters:@{} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 834 | 835 | MVLike *like = [[MVLike alloc] initWithDictionary:results]; 836 | success(like, response); 837 | 838 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 839 | failure(error, response); 840 | }]; 841 | } 842 | 843 | #pragma mark - Attachments 844 | 845 | - (void)getAttachmentsForShot:(NSInteger)shotID page:(NSInteger)page 846 | success:(SuccessHandler)success 847 | failure:(FailureHandler)failure 848 | { 849 | // List attachments for a shot 850 | // GET /shots/:id/attachments 851 | 852 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%@/attachments", kAPIBaseURL, @(shotID)]; 853 | 854 | [self GETOperationWithURL:urlString parameters:@{@"page": [NSNumber numberWithInteger:page]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 855 | 856 | NSMutableArray *attachmentsArray = [NSMutableArray array]; 857 | for (NSDictionary *dictionary in results) { 858 | MVAttachment *attachment = [[MVAttachment alloc] initWithDictionary:dictionary]; 859 | [attachmentsArray addObject:attachment]; 860 | } 861 | 862 | success(attachmentsArray, response); 863 | 864 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 865 | failure(error, response); 866 | }]; 867 | } 868 | 869 | - (void)getAttachmentWithID:(NSInteger)attachmentID onShot:(NSInteger)shotID 870 | success:(void (^)(MVAttachment *, NSHTTPURLResponse *))success 871 | failure:(FailureHandler)failure 872 | { 873 | // Get a single attachme 874 | // GET /shots/:shot/attachments/:id 875 | 876 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%@/attachments/%@", kAPIBaseURL, @(shotID), @(attachmentID)]; 877 | 878 | [self GETOperationWithURL:urlString parameters:nil success:^(NSDictionary *results, NSHTTPURLResponse *response) { 879 | 880 | MVAttachment *attachment = [[MVAttachment alloc] initWithDictionary:results]; 881 | success(attachment, response); 882 | 883 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 884 | failure(error, response); 885 | }]; 886 | } 887 | 888 | 889 | - (void)createAttachmentForShot:(NSInteger)shotID fromData:(NSData *)attachmentData 890 | success:(void (^)(MVAttachment *, NSHTTPURLResponse *))success 891 | failure:(FailureHandler)failure 892 | { 893 | // Create an attachment 894 | // POST /shots/:shot/attachments 895 | 896 | NSString *urlString = [NSString stringWithFormat:@"%@/%@/attachment", kAPIBaseURL, @(shotID)]; 897 | 898 | [self POSTOperationWithURL:urlString parameters:@{@"file": attachmentData} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 899 | 900 | MVAttachment *attachment = [[MVAttachment alloc] initWithDictionary:results]; 901 | success(attachment, response); 902 | 903 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 904 | failure(error, response); 905 | }]; 906 | } 907 | 908 | - (void)deleteAttachmetWithID:(NSInteger)attachmentID onShot:(NSInteger)shotID 909 | success:(void (^)(NSHTTPURLResponse *))success 910 | failure:(FailureHandler)failure 911 | { 912 | // Delete an attachment 913 | // DELETE /shots/:shot/attachments/:id 914 | 915 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%@/attachments/%@", kAPIBaseURL, @(shotID), @(attachmentID)]; 916 | 917 | [self DELETEOperationWithURL:urlString parameters:nil success:^(NSHTTPURLResponse *response) { 918 | 919 | success(response); 920 | 921 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 922 | failure(error, response); 923 | }]; 924 | } 925 | 926 | #pragma mark - Comments 927 | 928 | - (void)getCommentsForShot:(NSInteger)shotID page:(NSInteger)page 929 | success:(SuccessHandler)success 930 | failure:(FailureHandler)failure 931 | { 932 | // List comments for a shot 933 | // GET /shots/:shot/comments 934 | 935 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%@/comments", kAPIBaseURL, @(shotID)]; 936 | 937 | [self GETOperationWithURL:urlString parameters:@{@"page": [NSNumber numberWithInteger:page]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 938 | 939 | NSMutableArray *commentArray = [NSMutableArray array]; 940 | for (NSDictionary *dictionary in results) { 941 | MVComment *comment = [[MVComment alloc] initWithDictionary:dictionary]; 942 | [commentArray addObject:comment]; 943 | } 944 | 945 | success(commentArray, response); 946 | 947 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 948 | failure(error, response); 949 | }]; 950 | } 951 | 952 | - (void)getLikesForCommentWithID:(NSInteger)commentID onShot:(NSInteger)shotID page:(NSInteger)page 953 | success:(SuccessHandler)success 954 | failure:(FailureHandler)failure 955 | { 956 | // List likes for a comment 957 | // GET /shots/:shot/comments/:id/likes 958 | 959 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%@/comments/%@/likes", kAPIBaseURL, @(shotID), @(commentID)]; 960 | 961 | [self GETOperationWithURL:urlString parameters:@{@"page": [NSNumber numberWithInteger:page]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 962 | 963 | NSMutableArray *parsedResultsArray = [NSMutableArray array]; 964 | for (NSDictionary *dictionary in results) { 965 | MVLike *like = [[MVLike alloc] initWithDictionary:dictionary]; 966 | [parsedResultsArray addObject:like]; 967 | } 968 | 969 | success(parsedResultsArray, response); 970 | 971 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 972 | failure(error, response); 973 | }]; 974 | } 975 | 976 | - (void)createCommentForShot:(NSInteger)shotID body:(NSString *)body 977 | success:(void (^) (MVComment *, NSHTTPURLResponse *))success 978 | failure:(FailureHandler)failure 979 | { 980 | // Create a comment 981 | // POST /shots/:shot/comments 982 | 983 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%@/comments", kAPIBaseURL, @(shotID)]; 984 | 985 | [self POSTOperationWithURL:urlString parameters:@{@"body": body} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 986 | 987 | MVComment *comment = [[MVComment alloc] initWithDictionary:results]; 988 | success(comment, response); 989 | 990 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 991 | failure(error, response); 992 | }]; 993 | } 994 | 995 | - (void)getCommentWithID:(NSInteger)commentID onShot:(NSInteger)shotID 996 | success:(void (^)(MVComment *, NSHTTPURLResponse *))success 997 | failure:(FailureHandler)failure 998 | { 999 | // GET /shots/:shot/comments/:id 1000 | 1001 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%@/comments/%@", kAPIBaseURL, @(shotID), @(commentID)]; 1002 | 1003 | [self GETOperationWithURL:urlString parameters:@{} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 1004 | 1005 | MVComment *comment = [[MVComment alloc] initWithDictionary:results]; 1006 | success(comment, response); 1007 | 1008 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 1009 | failure(error, response); 1010 | }]; 1011 | } 1012 | 1013 | - (void)updateCommentWithID:(NSInteger)commentID onShot:(NSInteger)shotID body:(NSString *)body 1014 | success:(void (^)(MVComment *, NSHTTPURLResponse *))success 1015 | failure:(FailureHandler)failure 1016 | { 1017 | // Update a comment 1018 | // PUT /shots/:shot/comments/:id 1019 | 1020 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%@/comments/%@", kAPIBaseURL, @(shotID), @(commentID)]; 1021 | 1022 | [self PUTOperationWithURL:urlString parameters:@{@"body": body} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 1023 | 1024 | MVComment *comment= [[MVComment alloc] initWithDictionary:results]; 1025 | success(comment, response); 1026 | 1027 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 1028 | failure(error, response); 1029 | }]; 1030 | 1031 | } 1032 | 1033 | - (void)likeCommentWithID:(NSInteger)commentID onShot:(NSInteger)shotID 1034 | success:(void (^)(MVLike *, NSHTTPURLResponse *))success 1035 | failure:(FailureHandler)failure 1036 | { 1037 | // Like a comment 1038 | // POST /shots/:shot/comments/:id/like 1039 | 1040 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%@/comments/%@/like", kAPIBaseURL, @(shotID), @(commentID)]; 1041 | 1042 | [self POSTOperationWithURL:urlString parameters:@{@"shot_id": [NSNumber numberWithInteger:shotID], @"comment_id": [NSNumber numberWithInteger:commentID]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 1043 | 1044 | MVLike *like = [[MVLike alloc] initWithDictionary:results]; 1045 | success(like, response); 1046 | 1047 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 1048 | failure(error, response); 1049 | }]; 1050 | } 1051 | 1052 | - (void)unlikeCommentWithID:(NSInteger)commentID onShot:(NSInteger)shotID 1053 | success:(void (^)(NSHTTPURLResponse *))success 1054 | failure:(FailureHandler)failure 1055 | { 1056 | // Unlike a comment 1057 | // DELETE /shots/:shot/comments/:id/like 1058 | 1059 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%@/comments/%@/like", kAPIBaseURL, @(shotID), @(commentID)]; 1060 | 1061 | [self DELETEOperationWithURL:urlString parameters:nil success:^(NSHTTPURLResponse *response) { 1062 | 1063 | success(response); 1064 | 1065 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 1066 | failure(error, response); 1067 | }]; 1068 | } 1069 | 1070 | - (void)checkIfCommentIsLiked:(NSInteger)commentID onShot:(NSInteger)shotID 1071 | success:(void (^)(MVLike *, NSHTTPURLResponse *))success 1072 | failure:(FailureHandler)failure 1073 | { 1074 | // GET /shots/:shot/comments/:id/like 1075 | 1076 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%@/comments/%@/like", kAPIBaseURL, @(shotID), @(commentID)]; 1077 | 1078 | [self GETOperationWithURL:urlString parameters:@{} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 1079 | 1080 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 1081 | failure(error, response); 1082 | }]; 1083 | } 1084 | 1085 | #pragma mark - Rebounds 1086 | 1087 | - (void)getReboundsForShot:(NSInteger)shotID page:(NSInteger)page 1088 | success:(SuccessHandler)success 1089 | failure:(FailureHandler)failure 1090 | { 1091 | // List rebounds for a shot 1092 | // GET /shots/:id/rebounds 1093 | 1094 | NSString *urlString = [NSString stringWithFormat:@"%@/shots/%@/rebounds", kAPIBaseURL, @(shotID)]; 1095 | 1096 | [self GETOperationWithURL:urlString parameters:@{@"page": [NSNumber numberWithInteger:page]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 1097 | 1098 | NSMutableArray *reboundsArray = [NSMutableArray array]; 1099 | 1100 | for (NSDictionary *dictionary in results) { 1101 | MVShot *shot = [[MVShot alloc] initWithDictionary:dictionary]; 1102 | [reboundsArray addObject:shot]; 1103 | } 1104 | 1105 | success(reboundsArray, response); 1106 | 1107 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 1108 | failure(error, response); 1109 | }]; 1110 | } 1111 | 1112 | #pragma mark - Buckets 1113 | 1114 | - (void)getBucketWithID:(NSInteger)bucketID 1115 | success:(void (^)(MVBucket *, NSHTTPURLResponse *))success 1116 | failure:(FailureHandler)failure 1117 | { 1118 | // GET /buckets/:id 1119 | 1120 | NSString *urlString = [NSString stringWithFormat:@"%@/buckets/%@", kAPIBaseURL, @(bucketID)]; 1121 | 1122 | [self GETOperationWithURL:urlString parameters:@{} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 1123 | 1124 | MVBucket *bucket = [[MVBucket alloc] initWithDictionary:results]; 1125 | success(bucket, response); 1126 | 1127 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 1128 | failure(error, response); 1129 | }]; 1130 | } 1131 | 1132 | - (void)createBucketWithName:(NSString *)bucketName description:(NSString *)bucketDescription 1133 | success:(void (^)(MVBucket *, NSHTTPURLResponse *))success 1134 | failure:(FailureHandler)failure 1135 | { 1136 | // POST /buckets 1137 | 1138 | NSString *urlString = [NSString stringWithFormat:@"%@/buckets", kAPIBaseURL]; 1139 | 1140 | [self POSTOperationWithURL:urlString parameters:@{@"name": bucketName, @"description": bucketDescription} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 1141 | 1142 | MVBucket *bucket = [[MVBucket alloc] initWithDictionary:results]; 1143 | success(bucket, response); 1144 | 1145 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 1146 | failure(error, response); 1147 | }]; 1148 | } 1149 | 1150 | - (void)updateBucketWithID:(NSInteger)bucketID name:(NSString *)bucketName description:(NSString *)bucketDescription 1151 | success:(void (^)(MVBucket *, NSHTTPURLResponse *))success 1152 | failure:(FailureHandler)failure 1153 | { 1154 | // PUT /buckets/:id 1155 | 1156 | NSString *urlString = [NSString stringWithFormat:@"%@/buckets/%@", kAPIBaseURL, @(bucketID)]; 1157 | 1158 | [self PUTOperationWithURL:urlString parameters:@{@"name": bucketName, @"description": bucketDescription} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 1159 | 1160 | MVBucket *bucket = [[MVBucket alloc] initWithDictionary:results]; 1161 | success(bucket, response); 1162 | 1163 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 1164 | failure(error, response); 1165 | }]; 1166 | } 1167 | 1168 | - (void)deleteBucketWithID:(NSInteger)bucketID 1169 | success:(void (^)(NSHTTPURLResponse *))success 1170 | failure:(FailureHandler)failure 1171 | { 1172 | // DELETE /buckets/:id 1173 | 1174 | NSString *urlString = [NSString stringWithFormat:@"%@/buckets/%@", kAPIBaseURL, @(bucketID)]; 1175 | 1176 | [self DELETEOperationWithURL:urlString parameters:nil success:^(NSHTTPURLResponse *response) { 1177 | 1178 | success(response); 1179 | 1180 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 1181 | failure(error, response); 1182 | }]; 1183 | } 1184 | 1185 | - (void)getShotsInBucket:(NSInteger)bucketID page:(NSInteger)page 1186 | success:(SuccessHandler)success 1187 | failure:(FailureHandler)failure 1188 | { 1189 | // GET /bucket/:id/shots 1190 | 1191 | NSString *urlString = [NSString stringWithFormat:@"%@/buckets/%@/shots", kAPIBaseURL, @(bucketID)]; 1192 | 1193 | [self GETOperationWithURL:urlString parameters:@{@"page": [NSNumber numberWithInteger:page]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 1194 | 1195 | NSMutableArray *shotsArray = [NSMutableArray array]; 1196 | 1197 | for (NSDictionary *dictionary in results) { 1198 | MVShot *shot = [[MVShot alloc] initWithDictionary:dictionary]; 1199 | [shotsArray addObject:shot]; 1200 | } 1201 | 1202 | success(shotsArray, response); 1203 | 1204 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 1205 | failure(error, response); 1206 | }]; 1207 | } 1208 | 1209 | - (void)addShotToBucket:(NSInteger)shotID bucket:(NSInteger)bucketID 1210 | success:(void (^) (NSHTTPURLResponse *response))success 1211 | failure:(FailureHandler)failure 1212 | { 1213 | // PUT /buckets/:id/shots 1214 | 1215 | NSString *urlString = [NSString stringWithFormat:@"%@/buckets/%@/shots", kAPIBaseURL, @(bucketID)]; 1216 | 1217 | [self PUTOperationWithURL:urlString parameters:@{@"shot_id": [NSNumber numberWithInteger:shotID]} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 1218 | 1219 | success(response); 1220 | 1221 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 1222 | failure(error, response); 1223 | }]; 1224 | } 1225 | 1226 | // FIXME: Doesn't work 1227 | - (void)removeShotFromBucket:(NSInteger)shotID bucket:(NSInteger)bucketID 1228 | success:(void (^) (NSHTTPURLResponse *response))success 1229 | failure:(FailureHandler)failure 1230 | { 1231 | // DELETE /buckets/:id/shots 1232 | 1233 | NSString *urlString = [NSString stringWithFormat:@"%@/buckets/%@/shots", kAPIBaseURL, @(bucketID)]; 1234 | 1235 | [self DELETEOperationWithURL:urlString parameters:@{@"shot_id": [NSNumber numberWithInteger:shotID]} success:^(NSHTTPURLResponse *response) { 1236 | 1237 | 1238 | NSLog(@"%@", response); 1239 | NSLog(@"success"); 1240 | success(response); 1241 | 1242 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 1243 | failure(error, response); 1244 | NSLog(@"%@", response); 1245 | NSLog(@"error"); 1246 | }]; 1247 | } 1248 | 1249 | #pragma mark - Projects 1250 | 1251 | - (void)getProjectWithID:(NSInteger)projectID 1252 | success:(void (^)(MVProject *, NSHTTPURLResponse *))success 1253 | failure:(FailureHandler)failure 1254 | { 1255 | // GET /projects/:id 1256 | 1257 | NSString *urlString = [NSString stringWithFormat:@"%@/projects/%@", kAPIBaseURL, @(projectID)]; 1258 | 1259 | [self GETOperationWithURL:urlString parameters:@{} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 1260 | 1261 | MVProject *project = [[MVProject alloc] initWithDictionary:results]; 1262 | success(project, response); 1263 | 1264 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 1265 | failure(error, response); 1266 | }]; 1267 | } 1268 | 1269 | - (void)getShotsInProject:(NSInteger)projectID 1270 | success:(SuccessHandler)success 1271 | failure:(FailureHandler)failure 1272 | { 1273 | // GET /project/:id/shots 1274 | 1275 | NSString *urlString = [NSString stringWithFormat:@"%@/projects/%@/shots", kAPIBaseURL, @(projectID)]; 1276 | 1277 | [self GETOperationWithURL:urlString parameters:@{} success:^(NSDictionary *results, NSHTTPURLResponse *response) { 1278 | 1279 | NSMutableArray *shotsArray = [NSMutableArray array]; 1280 | 1281 | for (NSDictionary *dictionary in results) { 1282 | MVShot *shot = [[MVShot alloc] initWithDictionary:dictionary]; 1283 | [shotsArray addObject:shot]; 1284 | } 1285 | 1286 | success(shotsArray, response); 1287 | 1288 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 1289 | failure(error, response); 1290 | }]; 1291 | } 1292 | 1293 | - (void)createJobInOrganization:(NSString *)organizationName 1294 | jobPosition:(NSString *)jobTitle 1295 | location:(NSString *)jobLocation 1296 | detailURL:(NSString *)jobDetails 1297 | active:(BOOL)jobActive 1298 | success:(JobHandler)success 1299 | failure:(FailureHandler)failure 1300 | { 1301 | // POST /jobs 1302 | 1303 | NSString *urlString = [NSString stringWithFormat:@"%@/jobs", kAPIBaseURL]; 1304 | 1305 | NSDictionary *parameters = @{@"organization_name": organizationName, 1306 | @"title": jobTitle, 1307 | @"location": jobLocation, 1308 | @"url": jobDetails, 1309 | @"active": [NSNumber numberWithBool:jobActive]}; 1310 | 1311 | [self POSTOperationWithURL:urlString parameters:parameters success:^(NSDictionary *results, NSHTTPURLResponse *response) { 1312 | 1313 | MVJob *job = [[MVJob alloc] initWithDictionary:results]; 1314 | success(job, response); 1315 | 1316 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 1317 | failure(error, response); 1318 | }]; 1319 | } 1320 | 1321 | @end 1322 | 1323 | @implementation MVDribbbleKit (Private) 1324 | 1325 | #pragma mark - Private Methods 1326 | 1327 | - (NSString *)retrieveToken 1328 | { 1329 | if ([SSKeychain accountsForService:kDribbbbleKeychainService]) { 1330 | NSString *accountUsername = [[SSKeychain accountsForService:kDribbbbleKeychainService][0] 1331 | valueForKey:kSSKeychainAccountKey]; 1332 | 1333 | return [SSKeychain passwordForService:kDribbbbleKeychainService account:accountUsername]; 1334 | } else { 1335 | return nil; 1336 | } 1337 | } 1338 | 1339 | // FIXME: Needs fixed networking methods 1340 | // FIXME: Make it easier to use parameters because appending them to the urlString isn't nice enough 1341 | - (void)GETOperationWithURL:(NSString *)url parameters:(NSDictionary *)parameters 1342 | success:(void (^) (NSDictionary *, NSHTTPURLResponse *))success 1343 | failure:(void (^) (NSError *, NSHTTPURLResponse *))failure 1344 | { 1345 | NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 1346 | 1347 | NSString *tempTokenString = [NSString stringWithFormat:@"Bearer %@", [self retrieveToken]]; 1348 | configuration.HTTPAdditionalHeaders = @{@"Content-Type": @"application/json; charset=utf-8", 1349 | @"Authorization": tempTokenString}; 1350 | 1351 | 1352 | NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration]; 1353 | NSMutableString *finalMutableString = [NSMutableString stringWithFormat:@"%@?", url]; 1354 | 1355 | if (parameters) { 1356 | // Itterate over the parameters dictionary 1357 | for (id key in parameters) { 1358 | id value = parameters[key]; 1359 | [finalMutableString appendString:[NSString stringWithFormat:@"%@=%@&", key, value]]; 1360 | } 1361 | } else { 1362 | finalMutableString = [url copy]; 1363 | } 1364 | 1365 | if (parameters[@"page"]) { 1366 | // Append itemsPerPage 1367 | [finalMutableString appendString:[NSString stringWithFormat:@"per_page=%@", [_itemsPerPage stringValue]]]; 1368 | } 1369 | 1370 | [[session dataTaskWithURL:[NSURL URLWithString:finalMutableString] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 1371 | 1372 | NSHTTPURLResponse *convertedResponse = (NSHTTPURLResponse *)response; 1373 | 1374 | if (error == nil) { 1375 | NSError *jsonError = nil; 1376 | NSDictionary *serializedResults = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError]; 1377 | if (jsonError == nil) { 1378 | success(serializedResults, convertedResponse); 1379 | } else { 1380 | failure(jsonError, nil); 1381 | } 1382 | } else { 1383 | failure(error, convertedResponse); 1384 | } 1385 | }] resume]; 1386 | } 1387 | 1388 | - (void)PUTOperationWithURL:(NSString *)url parameters:(NSDictionary *)parameters 1389 | success:(void (^)(NSDictionary *, NSHTTPURLResponse *))success 1390 | failure:(void (^)(NSError *, NSHTTPURLResponse *))failure 1391 | { 1392 | NSString *tempTokenString = [NSString stringWithFormat:@"Bearer %@", [self retrieveToken]]; 1393 | 1394 | NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 1395 | configuration.HTTPAdditionalHeaders = @{@"Content-Type": @"application/json; charset=utf-8", @"Authorization": tempTokenString}; 1396 | 1397 | NSDictionary *tempParameters = [NSDictionary dictionary]; 1398 | 1399 | if (parameters == nil) { 1400 | tempParameters = @{@"": @""}; 1401 | } else { 1402 | tempParameters = parameters; 1403 | } 1404 | 1405 | NSError *error = nil; 1406 | NSData *parameterData = [NSJSONSerialization dataWithJSONObject:tempParameters options:0 error:&error]; 1407 | 1408 | if (error == nil) { 1409 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]]; 1410 | request.HTTPMethod = @"PUT"; 1411 | 1412 | NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration]; 1413 | 1414 | [[session uploadTaskWithRequest:request fromData:parameterData completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 1415 | 1416 | NSHTTPURLResponse *convertedResponse = (NSHTTPURLResponse *)response; 1417 | 1418 | if (error == nil) { 1419 | NSError *jsonError = nil; 1420 | NSDictionary *serializedResults = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError]; 1421 | 1422 | if (jsonError == nil) { 1423 | success(serializedResults, convertedResponse); 1424 | } else { 1425 | failure(error, nil); 1426 | } 1427 | 1428 | } else { 1429 | failure(error, convertedResponse); 1430 | } 1431 | 1432 | }] resume]; 1433 | } else { 1434 | failure(error, nil); 1435 | } 1436 | } 1437 | 1438 | - (void)POSTOperationWithURL:(NSString *)url parameters:(NSDictionary *)parameters 1439 | success:(void (^)(NSDictionary *, NSHTTPURLResponse *))success 1440 | failure:(void (^)(NSError *, NSHTTPURLResponse *))failure 1441 | { 1442 | NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 1443 | 1444 | NSString *tempTokenString = [NSString stringWithFormat:@"Bearer %@", [self retrieveToken]]; 1445 | 1446 | if ([self retrieveToken] == nil) { 1447 | configuration.HTTPAdditionalHeaders = @{@"Content-Type": @"application/json; charset=utf-8"}; 1448 | } else { 1449 | configuration.HTTPAdditionalHeaders = @{@"Content-Type": @"application/json; charset=utf-8", @"Authorization": tempTokenString}; 1450 | } 1451 | 1452 | NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration]; 1453 | NSDictionary *tempParameters = [NSDictionary dictionary]; 1454 | 1455 | 1456 | NSData *parameterData; 1457 | if (parameters == nil) { 1458 | tempParameters = @{@"": @""}; 1459 | } else { 1460 | NSMutableString *paras = [NSMutableString string]; 1461 | for (NSString *key in parameters) { 1462 | 1463 | NSString *myString = [NSString stringWithFormat:@"%@=%@&", key, parameters[key]]; 1464 | [paras appendString:myString]; 1465 | 1466 | } 1467 | parameterData = [paras dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; 1468 | } 1469 | 1470 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]]; 1471 | request.HTTPMethod = @"POST"; 1472 | 1473 | [[session uploadTaskWithRequest:request fromData:parameterData completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 1474 | 1475 | NSHTTPURLResponse *convertedResponse = (NSHTTPURLResponse *)response; 1476 | 1477 | if (error == nil) { 1478 | NSError *jsonError = nil; 1479 | NSDictionary *serializedResults = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError]; 1480 | 1481 | if (jsonError == nil) { 1482 | success(serializedResults, convertedResponse); 1483 | } else { 1484 | failure(error, nil); 1485 | } 1486 | 1487 | } else { 1488 | failure(error, convertedResponse); 1489 | } 1490 | 1491 | }] resume]; 1492 | } 1493 | 1494 | // FIXME: Doesn't work correctly 1495 | - (void)DELETEOperationWithURL:(NSString *)url parameters:(NSDictionary *)parameters 1496 | success:(void (^)(NSHTTPURLResponse *))success 1497 | failure:(void (^)(NSError *, NSHTTPURLResponse *))failure 1498 | { 1499 | NSString *tempTokenString = [NSString stringWithFormat:@"Bearer %@", [self retrieveToken]]; 1500 | 1501 | NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 1502 | configuration.HTTPAdditionalHeaders = @{@"Authorization": tempTokenString}; 1503 | 1504 | NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration]; 1505 | 1506 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]]; 1507 | request.HTTPMethod = @"DELETE"; 1508 | 1509 | [[session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 1510 | 1511 | NSHTTPURLResponse *convertedResponse = (NSHTTPURLResponse *)response; 1512 | 1513 | if (error == nil) { 1514 | success(convertedResponse); 1515 | } else { 1516 | failure(error, convertedResponse); 1517 | } 1518 | 1519 | }] resume]; 1520 | } 1521 | 1522 | @end -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVAttachment.h: -------------------------------------------------------------------------------- 1 | // MVAttachment.h 2 | // 3 | // Copyright (c) 2014-2015 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import 24 | 25 | #import "MVModel.h" 26 | 27 | @interface MVAttachment : MVModel 28 | 29 | @property (nonatomic) NSDate *createdDate; 30 | @property (nonatomic) NSNumber *attachmentID; 31 | @property (nonatomic) NSURL *attachmentURL; 32 | @property (nonatomic) NSNumber *viewsCount; 33 | @property (nonatomic) NSNumber *size; 34 | @property (nonatomic) NSString *contentType; 35 | 36 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVAttachment.m: -------------------------------------------------------------------------------- 1 | // MVAttachment.m 2 | // 3 | // Copyright (c) 2014-2015 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import "MVAttachment.h" 24 | 25 | @implementation MVAttachment 26 | 27 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 28 | { 29 | self = [super init]; 30 | if (self) { 31 | 32 | _attachmentID = [self objectForKeyOrNil:dictionary[@"id"]]; 33 | _attachmentURL = [self objectForKeyOrNil:[NSURL URLWithString:dictionary[@"url"]]]; 34 | _viewsCount = [self objectForKeyOrNil:dictionary[@"views_count"]]; 35 | _size = [self objectForKeyOrNil:dictionary[@"size"]]; 36 | _contentType = [self objectForKeyOrNil:dictionary[@"content_type"]]; 37 | 38 | _createdDate = [self.formatter dateFromString:dictionary[@"created_at"]]; 39 | 40 | } 41 | return self; 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVBucket.h: -------------------------------------------------------------------------------- 1 | // MVBucket.h 2 | // 3 | // Copyright (c) 2014-2015 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import 24 | 25 | #import "MVUser.h" 26 | #import "MVModel.h" 27 | 28 | @interface MVBucket : MVModel 29 | 30 | @property (nonatomic) NSNumber *bucketID; 31 | @property (nonatomic) NSString *bucketName; 32 | @property (nonatomic) NSString *bucketDescription; 33 | @property (nonatomic) NSNumber *shotsCount; 34 | @property (nonatomic) NSDate *createdDate; 35 | @property (nonatomic) NSDate *updatedDate; 36 | 37 | @property (nonatomic) MVUser *user; 38 | 39 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVBucket.m: -------------------------------------------------------------------------------- 1 | // MVBucket.m 2 | // 3 | // Copyright (c) 2014-2015 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import "MVBucket.h" 24 | 25 | @implementation MVBucket 26 | 27 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 28 | { 29 | self = [super init]; 30 | if (self) { 31 | _bucketID = [self objectForKeyOrNil:dictionary[@"id"]]; 32 | _bucketName = [self objectForKeyOrNil:dictionary[@"name"]]; 33 | _bucketDescription = [self objectForKeyOrNil:dictionary[@"description"]]; 34 | _shotsCount = [self objectForKeyOrNil:dictionary[@"shots_count"]]; 35 | _user = [[MVUser alloc] initWithDictionary:dictionary[@"user"]]; 36 | 37 | _createdDate = [self.formatter dateFromString:[dictionary objectForKey:@"created_at"]]; 38 | _updatedDate = [self.formatter dateFromString:[dictionary objectForKey:@"updated_at"]]; 39 | } 40 | return self; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVComment.h: -------------------------------------------------------------------------------- 1 | // MVComment.h 2 | // 3 | // Copyright (c) 2014-2015 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import 24 | 25 | #import "MVUser.h" 26 | #import "MVModel.h" 27 | 28 | @interface MVComment : MVModel 29 | 30 | @property (nonatomic) NSNumber *commentID; 31 | @property (nonatomic, copy) NSString *body; 32 | @property (nonatomic) NSNumber *likesCount; 33 | @property (nonatomic) NSURL *likesURL; 34 | @property (nonatomic) NSDate *createdDate; 35 | @property (nonatomic) MVUser *user; 36 | 37 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVComment.m: -------------------------------------------------------------------------------- 1 | // MVComment.m 2 | // 3 | // Copyright (c) 2014-2015 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import "MVComment.h" 24 | 25 | @implementation MVComment 26 | 27 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 28 | { 29 | self = [super init]; 30 | if (self) { 31 | 32 | _commentID = [self objectForKeyOrNil:dictionary[@"id"]]; 33 | _body = [self objectForKeyOrNil:dictionary[@"body"]]; 34 | _likesCount = [self objectForKeyOrNil:dictionary[@"likes_count"]]; 35 | _likesURL = [self objectForKeyOrNil:[NSURL URLWithString:dictionary[@"likes_url"]]]; 36 | 37 | // Parse the date 38 | // Example: 2014-07-02T15:46:06Z 39 | _createdDate = [self.formatter dateFromString:dictionary[@"created_at"]]; 40 | 41 | NSDictionary *userDictionary = dictionary[@"user"]; 42 | _user = [[MVUser alloc] initWithDictionary:userDictionary]; 43 | 44 | } 45 | return self; 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVJob.h: -------------------------------------------------------------------------------- 1 | // MVJob.h 2 | // 3 | // Copyright (c) 2014-2016 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import "MVModel.h" 24 | 25 | @interface MVJob : MVModel 26 | 27 | @property (nonatomic) NSNumber *jobID; 28 | @property (nonatomic) NSString *organizationName; 29 | @property (nonatomic) NSString *jobTitle; 30 | @property (nonatomic) NSString *jobLocation; 31 | @property (nonatomic) NSURL *jobURL; 32 | @property (nonatomic) NSDate *createdDate; 33 | @property (nonatomic) NSDate *updatedDate; 34 | 35 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVJob.m: -------------------------------------------------------------------------------- 1 | // MVJob.m 2 | // 3 | // Copyright (c) 2014-2016 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import "MVJob.h" 24 | 25 | @implementation MVJob 26 | 27 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 28 | { 29 | self = [super init]; 30 | if (self) { 31 | _jobID = [self objectForKeyOrNil:dictionary[@"id"]]; 32 | _organizationName = [self objectForKeyOrNil:dictionary[@"organization_name"]]; 33 | _jobTitle = [self objectForKeyOrNil:dictionary[@"title"]]; 34 | _jobLocation = [self objectForKeyOrNil:dictionary[@"location"]]; 35 | _jobURL = [NSURL URLWithString:[self objectForKeyOrNil:dictionary[@"url"]]]; 36 | 37 | _createdDate = [self.formatter dateFromString:dictionary[@"created_at"]]; 38 | _updatedDate = [self.formatter dateFromString:dictionary[@"updated_at"]]; 39 | } 40 | return self; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVLike.h: -------------------------------------------------------------------------------- 1 | // MVLike.h 2 | // 3 | // Copyright (c) 2014-2015 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import 24 | 25 | #import "MVUser.h" 26 | #import "MVModel.h" 27 | 28 | @interface MVLike : MVModel 29 | 30 | @property (nonatomic) NSDate *createdDate; 31 | @property (nonatomic) NSNumber *likeID; 32 | @property (nonatomic) MVUser *user; 33 | 34 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVLike.m: -------------------------------------------------------------------------------- 1 | // MVLike.m 2 | // 3 | // Copyright (c) 2014-2015 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import "MVLike.h" 24 | 25 | @implementation MVLike 26 | 27 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 28 | { 29 | self = [super init]; 30 | if (self) { 31 | _likeID = [self objectForKeyOrNil:dictionary[@"id"]]; 32 | _user = [[MVUser alloc] initWithDictionary:dictionary[@"user"]]; 33 | 34 | _createdDate = [self.formatter dateFromString:dictionary[@"created_at"]]; 35 | } 36 | return self; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVLikedShot.h: -------------------------------------------------------------------------------- 1 | // 2 | // MVLikedShot.h 3 | // Pods 4 | // 5 | // Created by Alkim Gozen on 06/06/15. 6 | // 7 | // 8 | 9 | #import "MVModel.h" 10 | 11 | @class MVShot; 12 | 13 | @interface MVLikedShot : MVModel 14 | @property (nonatomic) NSDate *createdDate; 15 | @property (nonatomic) NSNumber *likeID; 16 | @property (nonatomic) MVShot *shot; 17 | 18 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVLikedShot.m: -------------------------------------------------------------------------------- 1 | // 2 | // MVLikedShot.m 3 | // Pods 4 | // 5 | // Created by Alkim Gozen on 06/06/15. 6 | // 7 | // 8 | 9 | #import "MVLikedShot.h" 10 | #import "MVShot.h" 11 | 12 | @implementation MVLikedShot 13 | 14 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 15 | { 16 | self = [super init]; 17 | if (self) { 18 | _likeID = [self objectForKeyOrNil:dictionary[@"id"]]; 19 | _shot = [[MVShot alloc] initWithDictionary:dictionary[@"shot"]]; 20 | 21 | _createdDate = [self.formatter dateFromString:dictionary[@"created_at"]]; 22 | } 23 | return self; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVModel.h: -------------------------------------------------------------------------------- 1 | // MVModel.h 2 | // 3 | // Copyright (c) 2014-2015 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import 24 | 25 | @interface MVModel : NSObject 26 | 27 | @property (nonatomic) NSISO8601DateFormatter *formatter; 28 | 29 | - (id)objectForKeyOrNil:(id)key; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVModel.m: -------------------------------------------------------------------------------- 1 | // MVModel.m 2 | // 3 | // Copyright (c) 2014-2015 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import "MVModel.h" 24 | 25 | @implementation MVModel 26 | 27 | - (instancetype)init 28 | { 29 | self = [super init]; 30 | if (self) { 31 | _formatter = [[NSISO8601DateFormatter alloc] init]; 32 | } 33 | return self; 34 | } 35 | 36 | - (id)objectForKeyOrNil:(id)key 37 | { 38 | if (key) { 39 | if ([key isKindOfClass:[NSNull class]]) { 40 | return nil; 41 | } else { 42 | return key; 43 | } 44 | } else { 45 | return nil; 46 | } 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVProject.h: -------------------------------------------------------------------------------- 1 | // MVProject.h 2 | // 3 | // Copyright (c) 2014-2015 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import 24 | 25 | #import "MVUser.h" 26 | #import "MVModel.h" 27 | 28 | @interface MVProject : MVModel 29 | 30 | @property (nonatomic) NSNumber *projectID; 31 | @property (nonatomic) NSString *projectName; 32 | @property (nonatomic) NSString *projectDescription; 33 | @property (nonatomic) NSNumber *shotsCount; 34 | @property (nonatomic) NSDate *createdDate; 35 | @property (nonatomic) NSDate *updatedDate; 36 | 37 | @property (nonatomic) MVUser *user; 38 | 39 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVProject.m: -------------------------------------------------------------------------------- 1 | // MVProject.m 2 | // 3 | // Copyright (c) 2014-2015 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import "MVProject.h" 24 | 25 | @implementation MVProject 26 | 27 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 28 | { 29 | self = [super init]; 30 | if (self) { 31 | _projectID = [self objectForKeyOrNil:dictionary[@"id"]]; 32 | _projectName = [self objectForKeyOrNil:dictionary[@"id"]]; 33 | _projectDescription = [self objectForKeyOrNil:dictionary[@"description"]]; 34 | _shotsCount = [self objectForKeyOrNil:dictionary[@"shots_count"]]; 35 | _user = [[MVUser alloc] initWithDictionary:dictionary[@"user"]]; 36 | 37 | _createdDate = [self.formatter dateFromString:dictionary[@"created_at"]]; 38 | _updatedDate = [self.formatter dateFromString:dictionary[@"updated_at"]]; 39 | } 40 | return self; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVShot.h: -------------------------------------------------------------------------------- 1 | // MVShot.h 2 | // 3 | // Copyright (c) 2014-2015 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import 24 | 25 | #import "MVUser.h" 26 | #import "MVModel.h" 27 | 28 | @interface MVShot : MVModel 29 | 30 | @property (nonatomic) NSNumber *attachmentsCount; 31 | @property (nonatomic) NSURL *attachmentsURL; 32 | @property (nonatomic) NSNumber *bucketsCount; 33 | @property (nonatomic) NSNumber *commentsCount; 34 | 35 | @property (nonatomic) NSURL *commentsURL; 36 | @property (nonatomic) NSDate *createdDate; 37 | @property (nonatomic, copy) NSString *shotDescription; 38 | @property (nonatomic) NSURL *htmlURL; 39 | @property (nonatomic) NSNumber *shotID; 40 | 41 | @property (nonatomic) NSNumber *likesCount; 42 | @property (nonatomic) NSURL *likesURL; 43 | @property (nonatomic) NSNumber *reboundsCount; 44 | @property (nonatomic) NSURL *reboundsURL; 45 | @property (nonatomic) NSArray *tags; 46 | @property (nonatomic) NSURL *projectsURL; 47 | 48 | @property (nonatomic, copy) NSString *title; 49 | @property (nonatomic) NSDate *updatedDate; 50 | @property (nonatomic) NSNumber *viewsCount; 51 | 52 | @property (nonatomic) NSURL *highDPIImageURL; 53 | @property (nonatomic) NSURL *normalImageURL; 54 | @property (nonatomic) NSURL *teaserImageURL; 55 | 56 | @property (nonatomic) MVUser *team; 57 | @property (nonatomic) MVUser *user; 58 | 59 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary; 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVShot.m: -------------------------------------------------------------------------------- 1 | // MVShot.m 2 | // 3 | // Copyright (c) 2014-2015 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import "MVShot.h" 24 | 25 | @implementation MVShot 26 | 27 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 28 | { 29 | self = [super init]; 30 | if (self) { 31 | _attachmentsCount = [self objectForKeyOrNil:dictionary[@"attachments_count"]]; 32 | _attachmentsURL = [self objectForKeyOrNil:[NSURL URLWithString:dictionary[@"attachments_url"]]]; 33 | _bucketsCount = [self objectForKeyOrNil:dictionary[@"buckets_count"]]; 34 | _commentsCount = [self objectForKeyOrNil:dictionary[@"comments_count"]]; 35 | _commentsURL = [self objectForKeyOrNil:[NSURL URLWithString:dictionary[@"comments_url"]]]; 36 | _htmlURL = [self objectForKeyOrNil:[NSURL URLWithString:dictionary[@"html_url"]]]; 37 | _shotID = [self objectForKeyOrNil:dictionary[@"id"]]; 38 | _viewsCount = [self objectForKeyOrNil:dictionary[@"views_count"]]; 39 | _likesCount = [self objectForKeyOrNil:dictionary[@"likes_count"]]; 40 | _likesURL = [self objectForKeyOrNil:[NSURL URLWithString:dictionary[@"likes_url"]]]; 41 | _reboundsCount = [self objectForKeyOrNil:dictionary[@"rebounds_count"]]; 42 | _reboundsURL = [self objectForKeyOrNil:[NSURL URLWithString:dictionary[@"rebounds_url"]]]; 43 | _title = [self objectForKeyOrNil:dictionary[@"title"]]; 44 | _user = [[MVUser alloc] initWithDictionary:dictionary[@"user"]]; 45 | _shotDescription = [self objectForKeyOrNil:dictionary[@"description"]]; 46 | _projectsURL = [self objectForKeyOrNil:[NSURL URLWithString:dictionary[@"projects_url"]]]; 47 | _team = [[MVUser alloc] initWithDictionary:[self objectForKeyOrNil:dictionary[@"team"]]]; 48 | 49 | 50 | NSMutableArray *tagsArray = [NSMutableArray array]; 51 | for (NSString *tag in dictionary[@"tags"]) { 52 | [tagsArray addObject:tag]; 53 | } 54 | _tags = tagsArray; 55 | 56 | 57 | NSDictionary *images = [self objectForKeyOrNil:dictionary[@"images"]]; 58 | _highDPIImageURL = [NSURL URLWithString:[self objectForKeyOrNil:images[@"hidpi"]]]; 59 | _teaserImageURL = [NSURL URLWithString:[self objectForKeyOrNil:images[@"teaser"]]]; 60 | _normalImageURL = [NSURL URLWithString:[self objectForKeyOrNil:images[@"normal"]]]; 61 | 62 | _createdDate = [self.formatter dateFromString:dictionary[@"created_at"]]; 63 | _updatedDate = [self.formatter dateFromString:dictionary[@"updated_at"]]; 64 | } 65 | return self; 66 | } 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVUser.h: -------------------------------------------------------------------------------- 1 | // MVPlayer.h 2 | // 3 | // Copyright (c) 2014-2015 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import 24 | 25 | #import "MVModel.h" 26 | 27 | typedef NS_ENUM(NSInteger, AccountType) { 28 | AccountTypeTeam, 29 | AccountTypeUser, 30 | AccountTypePlayer, 31 | AccountTypeProspect 32 | }; 33 | 34 | @interface MVUser : MVModel 35 | 36 | @property (nonatomic) NSURL *avatarURL; 37 | @property (nonatomic, copy) NSString *bio; 38 | @property (nonatomic) NSDate *createdDate; 39 | @property (nonatomic) NSNumber *followersCount; 40 | @property (nonatomic) NSNumber *followingsCount; 41 | 42 | @property (nonatomic) NSURL *htmlURL; 43 | @property (nonatomic) NSURL *followersURL; 44 | @property (nonatomic) NSURL *followingURL; 45 | @property (nonatomic) NSURL *likesURL; 46 | @property (nonatomic) NSNumber *userID; 47 | @property (nonatomic) NSNumber *likesCount; 48 | 49 | @property (nonatomic) NSDictionary *links; 50 | @property (nonatomic, copy) NSString *location; 51 | @property (nonatomic, copy) NSString *name; 52 | @property (nonatomic, getter = isPro) BOOL pro; 53 | @property (nonatomic) NSNumber *shotsCount; 54 | 55 | @property (nonatomic) NSURL *shotsURL; 56 | @property (nonatomic) NSURL *teamsURL; 57 | @property (nonatomic) AccountType accountType; 58 | @property (nonatomic) NSDate *updatedDate; 59 | @property (nonatomic, copy) NSString *username; 60 | 61 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary; 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /MVDribbbleKit/Models/MVUser.m: -------------------------------------------------------------------------------- 1 | // MVPlayer.m 2 | // 3 | // Copyright (c) 2014-2015 Marcel Voss 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import "MVUser.h" 24 | 25 | @implementation MVUser 26 | 27 | - (instancetype)initWithDictionary:(NSDictionary *)dictionary 28 | { 29 | self = [super init]; 30 | if (self) { 31 | 32 | _avatarURL = [NSURL URLWithString:dictionary[@"avatar_url"]]; 33 | _bio = dictionary[@"bio"]; 34 | _followersCount = dictionary[@"followers_count"]; 35 | _followingsCount = dictionary[@"following_count"]; 36 | 37 | _htmlURL = [NSURL URLWithString:dictionary[@"html_url"]]; 38 | _followersURL = [NSURL URLWithString:dictionary[@"followers_url"]]; 39 | _followingURL = [NSURL URLWithString:dictionary[@"following_url"]]; 40 | _likesURL = [NSURL URLWithString:dictionary[@"likes_url"]]; 41 | 42 | _userID = dictionary[@"id"]; 43 | _likesCount = dictionary[@"likes_count"]; 44 | 45 | _location = dictionary[@"location"]; 46 | _name = dictionary[@"name"]; 47 | _shotsCount = dictionary[@"shots_count"]; 48 | _shotsURL = [NSURL URLWithString:dictionary[@"shots_url"]]; 49 | _teamsURL = [NSURL URLWithString:dictionary[@"teams_url"]]; 50 | _username = dictionary[@"username"]; 51 | 52 | _links = dictionary[@"links"]; 53 | 54 | if ([dictionary[@"type"] isEqualToString:@"Player"]) { 55 | _accountType = AccountTypePlayer; 56 | } else if ([dictionary[@"type"] isEqualToString:@"Team"]) { 57 | _accountType = AccountTypeTeam; 58 | } 59 | 60 | if ([dictionary[@"pro"] isEqualToNumber:[NSNumber numberWithBool:0]]) { 61 | _pro = NO; 62 | } else { 63 | _pro = YES; 64 | } 65 | 66 | _createdDate = [self.formatter dateFromString:dictionary[@"created_at"]]; 67 | _updatedDate = [self.formatter dateFromString:dictionary[@"updated_at"]]; 68 | } 69 | return self; 70 | } 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Logo 3 |

4 | 5 | ![](https://img.shields.io/cocoapods/v/MVDribbbleKit.svg) 6 | ![](https://img.shields.io/cocoapods/l/MVDribbbleKit.svg) 7 | ![](https://img.shields.io/cocoapods/p/MVDribbbleKit.svg) 8 | 9 | MVDribbbleKit is a modern, full-featured and well-documented Objective-C wrapper for the official [Dribbble API v1](https://dribbble.com/api). 10 | 11 | One of the main goals was to create a wrapper, that requires as few dependencies as possible. Apart from that, I also wanted to write clean code, provide a good documentation and guarantee stability. 12 | 13 | Make sure to read the [Terms & Guidelines](http://developer.dribbble.com/terms/) before using Dribbble's API. 14 | 15 | **Important:** this library requires **iOS 10 or later**. 16 | 17 | ## Installation 18 | ### CocoaPods 19 | MVDribbbleKit is available via [CocoaPods](http://cocoapods.org/). Add the following to your Podfile, install it and you are ready to go: 20 | 21 | ` 22 | pod 'MVDribbbleKit', '~> 0.2' 23 | ` 24 | 25 | ### Without CocoaPods 26 | Download the latest version, drop the MVDribbbleKit folder to your project and #import it. Then you have to do the same for the only thirdy party dependency: [SSKeychain](https://github.com/soffes/SSKeychain). 27 | 28 | ## Usage 29 | ### Authenticating 30 | In order to interact with the API, you have to [register your application](https://dribbble.com/account/applications/new). After the registration you'll get a client key and a client secret. Store them somewhere inside your source code. Then set the three parameters and call the authorization method: 31 | 32 | ``` objc 33 | [manager setClientID:@"Client ID" clientSecret:@"Client Secret" callbackURL:@"Callback URL"]; 34 | [manager authorizeWithCompletion:^(NSError *error, BOOL stored) { 35 | // Returns a boolean value with the result of saving the access token to the keychain 36 | }]; 37 | ``` 38 | 39 | The callbackURL has to be equal to the one you've set while registering your application on Dribbble. Otherwise the authorization process is going to fail. 40 | 41 | By default all four scopes (write, public, comment, upload) are selected. If you want to specify them you can do that by assigning their names as an array of strings to the scopes property: 42 | 43 | ``` objc 44 | manager.scopes = @[@"write", @"public", @"comment", @"upload"]; 45 | ``` 46 | 47 | **Reminder:** MVDribbbleKit stores the access token automatically to the keychain, so you don’t have to take care of that. 48 | 49 | ### Requests 50 | It is easy to make requests and if you have ever used AFNetworking you will feel right at home because the methods are very similar to AFNetworking's (but this library doesn't use AFNetworking at all). For example, you can follow a user with the following code: 51 | 52 | ``` objc 53 | [manager followUserWithID:@"simplebits" success:^(NSHTTPURLResponse *response) { 54 | NSLog(@"Response: %@", response); 55 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 56 | NSLog(@"Error: %@ \nResponse: %@", error, response); 57 | }]; 58 | ``` 59 | 60 | Yup, that's it. Everything else is similar to this. Let's take another example. Here's how to get the details for a user: 61 | 62 | ``` objc 63 | [manager getDetailsForUser:@"simplebits" success:^(MVUser *user, NSHTTPURLResponse *response) { 64 | NSLog(@"Username: %@ \nName: %@", user.username, user.name); 65 | } failure:^(NSError *error, NSHTTPURLResponse *response) { 66 | NSLog(@"Error: %@ \nResponse: %@", error, response); 67 | }]; 68 | ``` 69 | 70 | Easy, huh? 71 | 72 | ### Models 73 | There are also seven model classes available to make your life a bit easier. These will be used to wrap everything into native foundation objects. 74 | 75 | * MVLike 76 | * MVAttachment 77 | * MVComment 78 | * MVShot 79 | * MVUser 80 | * MVBucket 81 | * MVProject 82 | 83 | ## License 84 | MVDribbbleKit is released under the [MIT License](https://github.com/marcelvoss/MVDribbbleKit/blob/master/LICENSE.md). 85 | --------------------------------------------------------------------------------