Statistics
| Branch: | Tag: | Revision:

root / Classes / AccountDetailsViewController.m @ d4df8ad2

History | View | Annotate | Download (18.4 kB)

1
//
2
//  AccountDetailsViewController.m
3
//  OpenStack
4
//
5
//  Created by Mike Mayo on 10/7/10.
6
//  The OpenStack project is provided under the Apache 2.0 license.
7
//
8

    
9
#import "AccountDetailsViewController.h"
10
#import "Provider.h"
11
#import "RSTextFieldCell.h"
12
#import "OpenStackAccount.h"
13
#import "RootViewController.h"
14
#import "ProvidersViewController.h"
15
#import "OpenStackRequest.h"
16
#import "UIViewController+Conveniences.h"
17
#import "NSString+Conveniences.h"
18
#import "ActivityIndicatorView.h"
19
#import "OpenStackAppDelegate.h"
20
#import "UIColor+MoreColors.h"
21

    
22

    
23
#define kUsername 0
24
#define kAPIKey 1
25

    
26
#define kProviderName 0
27
#define kAuthEndpoint 1
28

    
29
@implementation AccountDetailsViewController
30

    
31
@synthesize provider, rootViewController, providersViewController, activityIndicatorView;
32
@synthesize userName, apiKey;
33

    
34
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
35
    return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) || (toInterfaceOrientation == UIInterfaceOrientationPortrait);
36
}
37

    
38
#pragma mark -
39
#pragma mark HTTP Response Handlers
40

    
41
- (void)authenticationSucceded:(OpenStackRequest *)request {
42
    [self.activityIndicatorView removeFromSuperview];
43

    
44
    if ([request isSuccess]) {        
45
        account.authToken = [[request responseHeaders] objectForKey:@"X-Auth-Token"];
46
        account.serversURL = [NSURL URLWithString:[[request responseHeaders] objectForKey:@"X-Server-Management-Url"]];
47
        NSString *filesStorageURL;
48
        if (![[request responseHeaders] objectForKey:@"X-Storage-URL"]) {
49
            filesStorageURL = [NSString stringWithFormat:@"%@/v1/%@",
50
                                         [account.hostURL absoluteString],
51
                                         [account username]];
52
            account.filesURL = [NSURL URLWithString:filesStorageURL];
53
        }
54
        else {
55
            account.filesURL = [NSURL URLWithString:[[request responseHeaders] objectForKey:@"X-Storage-Url"]];
56
        }
57
        
58
        account.pithosPublicLinkURLPrefix = account.hostURL;
59
        account.pithosLoginURLPrefix = [NSURL URLWithString:
60
                                        [[account.hostURL absoluteString]
61
                                         stringByAppendingString:@"/login"]];
62

    
63
        NSString *cdnStr = [[request responseHeaders] objectForKey:@"X-Cdn-Management-Url"];
64
        if (!cdnStr) {
65
            cdnStr = [[request responseHeaders] objectForKey:@"X-CDN-Management-Url"];
66
        }
67
        if (cdnStr) {
68
            account.cdnURL = [NSURL URLWithString:cdnStr];
69
        }
70
        [account persist];
71
        [rootViewController.tableView reloadData];
72
        [account refreshCollections];
73

    
74
        [self.navigationController dismissModalViewControllerAnimated:YES];
75
    } else {
76
        self.navigationItem.rightBarButtonItem.enabled = NO;
77
        [self alert:@"Authentication Failure" message:@"Please check your User Name and Token."];
78
    }
79
}
80

    
81
- (void)authenticationFailed:(OpenStackRequest *)request {
82
    [self.activityIndicatorView removeFromSuperview];
83
    self.navigationItem.rightBarButtonItem.enabled = YES;
84
    if ([request responseStatusCode] == 401) {
85
        [self alert:@"Authentication Failure" message:@"Please check your User Name and Token."];
86
    } else {
87
        [self failOnBadConnection];
88
    }
89
}
90

    
91
- (void)authenticate {
92
    
93
    BOOL valid = YES;
94
    
95
    if (customProvider) {
96
        valid = valid && providerNameTextField.text && ![@"" isEqualToString:providerNameTextField.text];
97
        if (!valid) {
98
            [self alert:nil message:@"Please enter a provider name."];
99
            self.navigationItem.rightBarButtonItem.enabled = YES;
100
            [providerNameTextField becomeFirstResponder];
101
        } else {
102
            valid = valid && apiEndpointTextField.text && ![@"" isEqualToString:apiEndpointTextField.text];
103
            if (!valid) {
104
                [self alert:nil message:@"Please enter an API authentication URL."];
105
                self.navigationItem.rightBarButtonItem.enabled = YES;
106
                [apiEndpointTextField becomeFirstResponder];
107
            } else {
108
                valid = valid && apiEndpointTextField.text && [apiEndpointTextField.text isURL];
109
                if (!valid) {
110
                    [self alert:nil message:@"Please enter a valid API authentication URL."];
111
                    self.navigationItem.rightBarButtonItem.enabled = YES;
112
                    [apiEndpointTextField becomeFirstResponder];
113
                } else {
114
                    valid = valid && usernameTextField.text && ![@"" isEqualToString:usernameTextField.text];
115
                    if (!valid) {
116
                        [self alert:nil message:@"Please enter your username."];
117
                        self.navigationItem.rightBarButtonItem.enabled = YES;
118
                        [usernameTextField becomeFirstResponder];
119
                    } else {
120
                        valid = valid && apiKeyTextField.text && ![@"" isEqualToString:apiKeyTextField.text];
121
                        if (!valid) {
122
                            [self alert:nil message:@"Please enter your token."];
123
                            self.navigationItem.rightBarButtonItem.enabled = YES;
124
                            [apiKeyTextField becomeFirstResponder];
125
                        } else {
126
                            account = [[OpenStackAccount alloc] init];
127
                            account.provider = provider;
128
                            
129
                            if (!account.provider) {
130
                                Provider *p = [[Provider alloc] init];
131
                                p.name = providerNameTextField.text;                                
132
                                
133
                                NSString *urlString = apiEndpointTextField.text;
134
                                if ([urlString characterAtIndex:[urlString length] - 1] == '/') {
135
                                    urlString = [urlString substringToIndex:[urlString length] - 1];
136
                                }
137
                                p.authEndpointURL = [NSURL URLWithString:[urlString stringByAppendingString:@"/v1"]];
138
                                account.provider = p;
139
                                [p release];
140
                            }
141
                            
142
                            account.username = usernameTextField.text;
143
                            account.apiKey = [NSString stringWithString:apiKeyTextField.text];
144
                            NSString *authEndPointURL = [account.provider.authEndpointURL absoluteString];
145
                            account.hostURL = [NSURL URLWithString:[authEndPointURL substringToIndex:[authEndPointURL rangeOfString:@"/v1"].location]];
146
                            
147
                            self.activityIndicatorView = [[[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:@"Authenticating..."] text:@"Authenticating..."] autorelease];
148
                            [self.activityIndicatorView addToView:self.view];
149
                            
150
                            OpenStackRequest *request = [OpenStackRequest authenticationRequest:account];
151
                            request.delegate = self;
152
                            request.didFinishSelector = @selector(authenticationSucceded:);
153
                            request.didFailSelector = @selector(authenticationFailed:);
154
                            [request startAsynchronous];
155
                        }
156
                    }
157
                }                
158
            }
159
        }
160
    } else {
161
        valid = valid && usernameTextField.text && ![@"" isEqualToString:usernameTextField.text];
162
        if (!valid) {
163
            [self alert:nil message:@"Please enter your username."];
164
            self.navigationItem.rightBarButtonItem.enabled = YES;
165
            [usernameTextField becomeFirstResponder];
166
        } else {
167
            valid = valid && apiKeyTextField.text && ![@"" isEqualToString:apiKeyTextField.text];
168
            if (!valid) {
169
                [self alert:nil message:@"Please enter your token."];
170
                self.navigationItem.rightBarButtonItem.enabled = YES;
171
                [apiKeyTextField becomeFirstResponder];
172
            } else {
173
                account = [[OpenStackAccount alloc] init];                
174
                account.provider = provider;
175
                account.username = usernameTextField.text;
176
                account.apiKey = apiKeyTextField.text;
177
                NSString *authEndPointURL = [account.provider.authEndpointURL absoluteString];
178
                account.hostURL = [NSURL URLWithString:[authEndPointURL substringToIndex:[authEndPointURL rangeOfString:@"/v1"].location]];
179
                            
180
                self.activityIndicatorView = [[[ActivityIndicatorView alloc] initWithFrame:[ActivityIndicatorView frameForText:@"Authenticating..."] text:@"Authenticating..."] autorelease];
181
                [self.activityIndicatorView addToView:self.view];
182
                
183
                OpenStackRequest *request = [OpenStackRequest authenticationRequest:account];
184
                request.delegate = self;
185
                request.didFinishSelector = @selector(authenticationSucceded:);
186
                request.didFailSelector = @selector(authenticationFailed:);
187
                [request startAsynchronous];
188
            }
189
        }
190
    }
191
}
192

    
193
#pragma mark -
194
#pragma mark Button Handlers
195

    
196
- (void)saveButtonPressed:(id)sender {
197
    self.navigationItem.rightBarButtonItem.enabled = NO;
198
    tableShrunk = NO;
199
    CGRect rect = self.tableView.frame;
200
    rect.size.height = 416.0;
201
    self.tableView.frame = rect;
202
    [self authenticate];
203
}
204

    
205
#pragma mark - View lifecycle
206

    
207
- (void)viewDidLoad {
208
    [super viewDidLoad];
209

    
210
    self.navigationItem.title = @"Authentication";
211
    providerSection = -1;
212
    authenticationSection = 0;
213
    getTokenSection = 1;
214
    [self addSaveButton];
215
}
216

    
217
- (void)viewWillAppear:(BOOL)animated {
218
    [super viewWillAppear:animated];
219
    
220
    if (provider == nil) {
221
        customProvider = YES;
222
        providerSection = 0;
223
        authenticationSection = 1;
224
        getTokenSection = 2;
225
        [self.tableView reloadData];
226
    } 
227
    
228
}
229

    
230
- (void)viewDidAppear:(BOOL)animated {
231
    [super viewDidAppear:animated];
232
    [customProvider ? providerNameTextField : usernameTextField becomeFirstResponder];
233
}
234

    
235
- (void)viewWillDisappear:(BOOL)animated {
236
    [super viewWillDisappear:animated];
237
    [usernameTextField resignFirstResponder];
238
    [apiKeyTextField resignFirstResponder];
239
    [providerNameTextField resignFirstResponder];
240
    [apiEndpointTextField resignFirstResponder];
241
    tableShrunk = NO;
242
    CGRect rect = self.tableView.frame;
243
    rect.size.height = 416.0;
244
    self.tableView.frame = rect;
245
}
246

    
247
#pragma mark -
248
#pragma mark Table view data source
249

    
250
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
251
    if (customProvider)
252
        return 3;
253
    else
254
        return 2;
255
}
256

    
257
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
258
    if (section == getTokenSection)
259
        return 1;
260
    else 
261
        return 2;
262
}
263

    
264
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
265
    if (section == authenticationSection) {
266
        if (customProvider) {
267
            return @"Login";
268
        } else {
269
            return [NSString stringWithFormat:@"%@ Login", provider.name];
270
        }
271
    } else if (section == providerSection) {
272
        return @"Provider Details";
273
    } else {
274
        return @"";
275
    }
276
}
277

    
278
- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
279
    if (customProvider) {
280
        return @"";
281
    } else {
282
        return provider.authHelpMessage;
283
    }
284
}
285

    
286
- (RSTextFieldCell *)textCell:(NSString *)labelText textField:(UITextField **)textField secure:(BOOL)secure returnKeyType:(UIReturnKeyType)returnKeyType {
287

    
288
    RSTextFieldCell *cell = (RSTextFieldCell *)[self.tableView dequeueReusableCellWithIdentifier:labelText];
289
    
290
    if (cell == nil) {
291
        if ([labelText isEqualToString:@"API URL"])
292
            cell = [[[RSTextFieldCell alloc] initCellWithFixedLabel:@"/v1" withStyle:UITableViewCellStyleValue1
293
                                                    reuseIdentifier:labelText] autorelease];
294
        else 
295
            cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1
296
                                           reuseIdentifier:labelText] autorelease];
297
        
298
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
299
        cell.modalPresentationStyle = UIModalPresentationFormSheet;
300
        cell.textLabel.text = labelText;
301
        *textField = cell.textField;
302
        ((UITextField *)*textField).delegate = self;
303
        ((UITextField *)*textField).secureTextEntry = secure;
304
        ((UITextField *)*textField).returnKeyType = returnKeyType;
305
        if ([labelText isEqualToString:@"Username"])
306
            (*textField).text = userName;
307
        else if ([labelText isEqualToString:@"Token"])
308
            (*textField).text = apiKey;
309
    }
310
    
311
    return cell;
312
}
313

    
314
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
315
    
316
    
317
    UITableViewCell *cell = nil;
318
    
319
    if (indexPath.section == authenticationSection) {
320
        
321
        if (indexPath.row == kUsername) {
322
            if (userName)
323
                usernameTextField.text = userName;
324
            cell = [self textCell:@"Username" textField:&usernameTextField secure:NO returnKeyType:UIReturnKeyNext];
325
            if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
326
                CGRect rect = usernameTextField.frame;
327
                CGFloat offset = 19.0;
328
                usernameTextField.frame = CGRectMake(rect.origin.x + offset, rect.origin.y, rect.size.width - offset, rect.size.height);
329
            }
330
            
331
        } else if (indexPath.row == kAPIKey) {
332
            if (apiKey)
333
                apiKeyTextField.text = apiKey;
334
                cell = [self textCell:@"Token" textField:&apiKeyTextField secure:YES returnKeyType:UIReturnKeyDone];
335
        }
336
        
337
    } else if (indexPath.section == providerSection) {
338
        
339
        if (indexPath.row == kProviderName) {
340
            
341
            cell = [self textCell:@"Name" textField:&providerNameTextField secure:NO returnKeyType:UIReturnKeyNext];
342
            providerNameTextField.placeholder = @"Ex: Pithos";
343
            
344
        } else if (indexPath.row == kAuthEndpoint) {
345
            cell = [self textCell:@"API URL" textField:&apiEndpointTextField secure:NO returnKeyType:UIReturnKeyNext];
346
            apiEndpointTextField.placeholder = @"Type server's url here";            
347
        }
348
        
349
    } else if (indexPath.section == getTokenSection) {
350
        static NSString *CellIdentifier = @"Cell";
351
        
352
        cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
353
        if (cell == nil) {
354
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
355
        }
356
        
357
        cell.textLabel.text = @"Get Token";
358
    }
359
    
360
    return cell;
361
}
362

    
363
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
364
    if (indexPath.section == getTokenSection) {
365
        NSString *loginURLPrefix = @"";
366
        if (customProvider) {
367
            if (!apiEndpointTextField.text || (apiEndpointTextField.text && apiEndpointTextField.text.length == 0))
368
                [self alert:@"No API URL" message:@"Please enter an API URL"];
369
            else 
370
                loginURLPrefix = [apiEndpointTextField.text stringByAppendingString:@"/login"];
371
        } else
372
            loginURLPrefix = [[provider.authEndpointURL absoluteString] stringByReplacingOccurrencesOfString:@"/v1" withString:@"/login"];
373

    
374
        if (loginURLPrefix.length > 0) {
375
            NSString *loginURL = [NSString stringWithFormat:@"%@?next=pithos://login&force=", loginURLPrefix]; 
376

    
377
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:loginURL]];
378
        }
379
        [tableView deselectRowAtIndexPath:indexPath animated:NO];
380
        if (tableShrunk) {
381
            tableShrunk = NO;
382
            CGRect rect = self.tableView.frame;
383
            rect.size.height = 416.0;
384
            self.tableView.frame = rect;
385
        }
386
    }
387
}
388

    
389
#pragma mark -
390
#pragma mark Text Field Delegate
391

    
392
- (void)tableShrinkAnimationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
393
    UITextField *textField = ((UITextField *)context);
394
    if ([textField isEqual:apiKeyTextField] || [textField isEqual:usernameTextField]) {
395
        [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:kAPIKey inSection:authenticationSection] atScrollPosition:UITableViewScrollPositionNone animated:NO];
396
    }
397
}
398

    
399
- (void)textFieldDidBeginEditing:(UITextField *)textField {    
400
    if (!tableShrunk) {
401
        if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) {
402
            [UIView beginAnimations:nil context:textField];
403
            [UIView setAnimationDuration:0.35];
404
            [UIView setAnimationDelegate:self];
405
            [UIView setAnimationDidStopSelector:@selector(tableShrinkAnimationDidStop:finished:context:)];
406
            CGRect rect = self.tableView.frame;
407
            rect.size.height = 200.0;
408
            self.tableView.frame = rect;
409
            [UIView commitAnimations];
410
            tableShrunk = YES;
411
        }
412
    }
413
}
414

    
415
- (BOOL)textFieldShouldReturn:(UITextField *)textField {    
416

    
417
    if ([textField isEqual:providerNameTextField]) {
418
        [apiEndpointTextField becomeFirstResponder];
419
    } else if ([textField isEqual:apiEndpointTextField]) {
420
        [usernameTextField becomeFirstResponder];
421
        [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:kAPIKey inSection:authenticationSection] atScrollPosition:UITableViewScrollPositionNone animated:YES];
422
    } else if ([textField isEqual:usernameTextField]) {
423
        [apiKeyTextField becomeFirstResponder];
424
        [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:kAPIKey inSection:authenticationSection] atScrollPosition:UITableViewScrollPositionNone animated:YES];
425
    } else {
426
        [textField resignFirstResponder];
427
        self.navigationItem.rightBarButtonItem.enabled = NO;        
428
        tableShrunk = NO;
429
        CGRect rect = self.tableView.frame;
430
        rect.size.height = 416.0;
431
        self.tableView.frame = rect;
432
        [self authenticate];
433
    }
434
    return NO;
435
}
436

    
437
#pragma mark -
438
#pragma mark Memory management
439

    
440
- (void)dealloc {
441
    [provider release];
442
    [rootViewController release];
443
    [providersViewController release];
444
    [activityIndicatorView release];
445
    [userName release];
446
    [apiKey release];
447
    [super dealloc];
448
}
449

    
450
@end