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 |