@interface AccountDetailsViewController : UITableViewController <UITextFieldDelegate> {
Provider *provider;
- UITextField *usernameTextField;
- UITextField *authTokenTextField;
UITextField *providerNameTextField;
- UITextField *apiEndpointTextField;
+ UITextField *providerAuthURLTextField;
+ UITextField *providerPithosObjectStoreURLTextField;
+ UITextField *providerAstakosAccountURLTextField;
+ UITextField *providerAstakosWebloginURLTextField;
+ UISwitch *providerManualSwitch;
+
+ UITextField *authTokenTextField;
+ UITextField *usernameTextField;
+
+ UISwitch *ignoreSSLErrorsSwitch;
+
RootViewController *rootViewController;
+ NSString *providerName;
+ NSString *providerAuthURLString;
+ NSString *providerPithosObjectStoreURLString;
+ NSString *providerAstakosAccountURLString;
+ NSString *providerAstakosWebloginURLString;
+
NSString *username;
NSString *authToken;
+
BOOL customProvider;
- NSInteger authenticationSection;
NSInteger providerSection;
+ NSInteger authenticationSection;
NSInteger getTokenSection;
+ NSInteger optionsSection;
- OpenStackAccount *account;
+ OpenStackAccount *account;
}
-@property (nonatomic, retain) Provider *provider;
+@property (nonatomic, copy) Provider *provider;
@property (nonatomic, retain) RootViewController *rootViewController;
-@property (nonatomic, retain) NSString *username;
@property (nonatomic, retain) NSString *authToken;
+@property (nonatomic, retain) NSString *username;
-- (void)setUsername:(NSString *)aUsername andAuthToken:(NSString *)anAuthToken;
- (void)saveButtonPressed:(id)sender;
@end
#import "OpenStackAppDelegate.h"
#import "UIColor+MoreColors.h"
-#define kUsername 0
-#define kAuthToken 1
-
#define kProviderName 0
-#define kAuthEndpoint 1
+#define kProviderManualSwitch 1
+#define kProviderAuthURLOrPithosObjectStoreURL 2
+#define kProviderAstakosAccountURL 3
+#define kProviderAstakosWebloginURL 4
+
+#define kAuthToken 0
+#define kUsername 1
+
+#define kIgnoreSSLErrorsSwitch 0
+
+@interface AccountDetailsViewController()
+@property (nonatomic, retain) UITextField *providerNameTextField;
+@property (nonatomic, retain) UITextField *providerAuthURLTextField;
+@property (nonatomic, retain) UITextField *providerPithosObjectStoreURLTextField;
+@property (nonatomic, retain) UITextField *providerAstakosAccountURLTextField;
+@property (nonatomic, retain) UITextField *providerAstakosWebloginURLTextField;
+
+@property (nonatomic, retain) UITextField *authTokenTextField;
+@property (nonatomic, retain) UITextField *usernameTextField;
+
+@property (nonatomic, retain) NSString *providerName;
+@property (nonatomic, retain) NSString *providerAuthURLString;
+@property (nonatomic, retain) NSString *providerPithosObjectStoreURLString;
+@property (nonatomic, retain) NSString *providerAstakosAccountURLString;
+@property (nonatomic, retain) NSString *providerAstakosWebloginURLString;
+@end
@implementation AccountDetailsViewController
@synthesize provider, rootViewController;
-@synthesize username, authToken;
+@synthesize authToken, username;
+@synthesize providerNameTextField, providerAuthURLTextField, providerPithosObjectStoreURLTextField, providerAstakosAccountURLTextField,
+ providerAstakosWebloginURLTextField;
+@synthesize authTokenTextField, usernameTextField;
+@synthesize providerName, providerAuthURLString, providerPithosObjectStoreURLString, providerAstakosAccountURLString,
+ providerAstakosWebloginURLString;
#pragma mark - View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = @"Authentication";
+ self.navigationItem.rightBarButtonItem.enabled = NO;
providerSection = -1;
authenticationSection = 0;
getTokenSection = 1;
+ optionsSection = 2;
[self addSaveButton];
+
+ ignoreSSLErrorsSwitch = [[UISwitch alloc] init];
+ ignoreSSLErrorsSwitch.on = NO;
}
- (void)viewWillAppear:(BOOL)animated {
- [super viewWillAppear:animated];
- if (provider == nil) {
+ if (!provider) {
customProvider = YES;
providerSection = 0;
authenticationSection = 1;
getTokenSection = 2;
- [self.tableView reloadData];
+ optionsSection = 3;
+ provider = [[Provider alloc] init];
+
+ providerManualSwitch = [[UISwitch alloc] init];
+ [providerManualSwitch addTarget:self action:@selector(providerManualSwitchChanged:) forControlEvents:UIControlEventValueChanged];
+ providerManualSwitch.on = provider.manual;
}
+ [super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
- [customProvider ? providerNameTextField : usernameTextField becomeFirstResponder];
+ [customProvider ? providerNameTextField : authTokenTextField becomeFirstResponder];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
+ [providerNameTextField resignFirstResponder];
+ [providerAuthURLTextField resignFirstResponder];
+ [providerPithosObjectStoreURLTextField resignFirstResponder];
+ [providerAstakosAccountURLTextField resignFirstResponder];
+ [providerAstakosWebloginURLTextField resignFirstResponder];
[usernameTextField resignFirstResponder];
[authTokenTextField resignFirstResponder];
- [providerNameTextField resignFirstResponder];
- [apiEndpointTextField resignFirstResponder];
}
#pragma mark - Memory management
- (void)dealloc {
+ [account release];
[provider release];
[rootViewController release];
- [username release];
+ [providerNameTextField release];
+ [providerAuthURLTextField release];
+ [providerPithosObjectStoreURLTextField release];
+ [providerAstakosAccountURLTextField release];
+ [providerAstakosWebloginURLTextField release];
+ [authTokenTextField release];
+ [usernameTextField release];
[authToken release];
+ [username release];
+ [providerName release];
+ [providerAuthURLString release];
+ [providerPithosObjectStoreURLString release];
+ [providerAstakosAccountURLString release];
+ [providerAstakosWebloginURLString release];
+ [providerManualSwitch release];
+ [ignoreSSLErrorsSwitch release];
[super dealloc];
}
+#pragma mark - Internal
+
+- (void)providerManualSwitchChanged:(id)sender {
+ provider.manual = providerManualSwitch.on;
+ [self.tableView reloadData];
+}
+
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
- if (customProvider)
- return 3;
- else
- return 2;
+ return (customProvider ? 4 : 3);
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
- if (section == getTokenSection)
+ if (section == authenticationSection) {
+ return (provider.manual ? 2 : 1);
+ } else if (section == providerSection) {
+ return (provider.manual ? 5 : 3);
+ } else {
return 1;
- else
- return 2;
+ }
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
} else {
return [NSString stringWithFormat:@"%@ Login", provider.name];
}
+ } else if (section == optionsSection) {
+ return @"Options";
} else if (section == providerSection) {
return @"Provider Details";
} else {
- return @"";
+ return nil;
}
}
-- (RSTextFieldCell *)textCell:(NSString *)labelText textField:(UITextField **)textField secure:(BOOL)secure returnKeyType:(UIReturnKeyType)returnKeyType {
- RSTextFieldCell *cell = (RSTextFieldCell *)[self.tableView dequeueReusableCellWithIdentifier:labelText];
-
- if (cell == nil) {
- if ([labelText isEqualToString:@"API URL"])
- cell = [[[RSTextFieldCell alloc] initCellWithFixedLabel:@"/v1" withStyle:UITableViewCellStyleValue1
- reuseIdentifier:labelText] autorelease];
- else
- cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1
- reuseIdentifier:labelText] autorelease];
-
- cell.selectionStyle = UITableViewCellSelectionStyleNone;
+- (RSTextFieldCell *)textFieldCellWithReuseIdentifier:(NSString *)reuseIdentifier {
+ RSTextFieldCell *cell = (RSTextFieldCell *)[self.tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
+ if (!cell) {
+ cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier] autorelease];
cell.modalPresentationStyle = UIModalPresentationFormSheet;
- cell.textLabel.text = labelText;
- *textField = cell.textField;
- ((UITextField *)*textField).delegate = self;
- ((UITextField *)*textField).secureTextEntry = secure;
- ((UITextField *)*textField).returnKeyType = returnKeyType;
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
-
return cell;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
-
if (indexPath.section == authenticationSection) {
- if (indexPath.row == kUsername) {
- cell = [self textCell:@"UUID" textField:&usernameTextField secure:NO returnKeyType:UIReturnKeyNext];
- if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
- CGRect rect = usernameTextField.frame;
- CGFloat offset = 19.0;
- usernameTextField.frame = CGRectMake(rect.origin.x + offset, rect.origin.y, rect.size.width - offset, rect.size.height);
+ if (indexPath.row == kAuthToken) {
+ static NSString *CellIdentifier = @"AuthTokenCell";
+ cell = (RSTextFieldCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
+ ((RSTextFieldCell *)cell).modalPresentationStyle = UIModalPresentationFormSheet;
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.textLabel.text = @"Token";
+ self.authTokenTextField = ((RSTextFieldCell *)cell).textField;
+ if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
+ CGRect rect = authTokenTextField.frame;
+ CGFloat offset = 19.0;
+ authTokenTextField.frame = CGRectMake(rect.origin.x + offset, rect.origin.y, rect.size.width - offset, rect.size.height);
+ }
+ authTokenTextField.placeholder = @"Input or retrieve";
+ authTokenTextField.delegate = self;
}
- if (username)
- usernameTextField.text = username;
- } else if (indexPath.row == kAuthToken) {
- cell = [self textCell:@"Token" textField:&authTokenTextField secure:NO returnKeyType:UIReturnKeyDone];
+ authTokenTextField.returnKeyType = (provider.manual ? UIReturnKeyNext : UIReturnKeyDone);
if (authToken)
authTokenTextField.text = authToken;
- }
- } else if (indexPath.section == providerSection) {
- if (indexPath.row == kProviderName) {
- cell = [self textCell:@"Name" textField:&providerNameTextField secure:NO returnKeyType:UIReturnKeyNext];
- providerNameTextField.placeholder = @"E.g.: pithos";
- } else if (indexPath.row == kAuthEndpoint) {
- cell = [self textCell:@"API URL" textField:&apiEndpointTextField secure:NO returnKeyType:UIReturnKeyNext];
- apiEndpointTextField.placeholder = @"Type server's URL here";
+ } else if (indexPath.row == kUsername) {
+ static NSString *CellIdentifier = @"UsernameCell";
+ cell = (RSTextFieldCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
+ ((RSTextFieldCell *)cell).modalPresentationStyle = UIModalPresentationFormSheet;
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.textLabel.text = @"UUID";
+ self.usernameTextField = ((RSTextFieldCell *)cell).textField;
+ usernameTextField.placeholder = @"Input or retrieve";
+ usernameTextField.returnKeyType = UIReturnKeyDone;
+ usernameTextField.delegate = self;
+ }
+ if (username)
+ usernameTextField.text = username;
}
} else if (indexPath.section == getTokenSection) {
static NSString *CellIdentifier = @"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
- if (cell == nil) {
+ if (!cell) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
- cell.textLabel.text = @"Get Token";
+ cell.textLabel.textAlignment = UITextAlignmentCenter;
+ cell.textLabel.text = @"Retrieve Token";
+ } else if (indexPath.section == optionsSection) {
+ if (indexPath.row == kIgnoreSSLErrorsSwitch) {
+ static NSString *CellIdentifier = @"SwitchCell";
+ cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ }
+ cell.textLabel.text = @"Ignore SSL Errors";
+ cell.accessoryView = ignoreSSLErrorsSwitch;
+ }
+ } else if (indexPath.section == providerSection) {
+ if (indexPath.row == kProviderName) {
+ static NSString *CellIdentifier = @"ProviderNameCell";
+ cell = (RSTextFieldCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
+ ((RSTextFieldCell *)cell).modalPresentationStyle = UIModalPresentationFormSheet;
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.textLabel.text = @"Name";
+ self.providerNameTextField = ((RSTextFieldCell *)cell).textField;
+ providerNameTextField.placeholder = @"E.g.: pithos";
+ providerNameTextField.returnKeyType = UIReturnKeyNext;
+ providerNameTextField.delegate = self;
+ }
+ providerNameTextField.text = providerName;
+ } else if (indexPath.row == kProviderManualSwitch) {
+ static NSString *CellIdentifier = @"SwitchCell";
+ cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ }
+ cell.textLabel.text = @"Manual";
+ cell.accessoryView = providerManualSwitch;
+ } else if (indexPath.row == kProviderAuthURLOrPithosObjectStoreURL) {
+ if (providerManualSwitch.on) {
+ static NSString *CellIdentifier = @"ProviderPithosObjectStoreURLCell";
+ cell = (RSTextFieldCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
+ ((RSTextFieldCell *)cell).modalPresentationStyle = UIModalPresentationFormSheet;
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.textLabel.text = @"Pithos URL";
+ self.providerPithosObjectStoreURLTextField = ((RSTextFieldCell *)cell).textField;
+ providerPithosObjectStoreURLTextField.placeholder = @"Required";
+ providerPithosObjectStoreURLTextField.keyboardType = UIKeyboardTypeURL;
+ providerPithosObjectStoreURLTextField.returnKeyType = UIReturnKeyNext;
+ providerPithosObjectStoreURLTextField.delegate = self;
+ }
+ providerPithosObjectStoreURLTextField.text = providerPithosObjectStoreURLString;
+ } else {
+ static NSString *CellIdentifier = @"ProviderAuthURLCell";
+ cell = (RSTextFieldCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
+ ((RSTextFieldCell *)cell).modalPresentationStyle = UIModalPresentationFormSheet;
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.textLabel.text = @"Auth URL";
+ self.providerAuthURLTextField = ((RSTextFieldCell *)cell).textField;
+ providerAuthURLTextField.placeholder = @"Required";
+ providerAuthURLTextField.keyboardType = UIKeyboardTypeURL;
+ providerAuthURLTextField.returnKeyType = UIReturnKeyNext;
+ providerAuthURLTextField.delegate = self;
+ }
+ providerAuthURLTextField.text = providerAuthURLString;
+ }
+ } else if (indexPath.row == kProviderAstakosAccountURL) {
+ static NSString *CellIdentifier = @"ProviderAstakosAccountURLCell";
+ cell = (RSTextFieldCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
+ ((RSTextFieldCell *)cell).modalPresentationStyle = UIModalPresentationFormSheet;
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.textLabel.text = @"Astakos URL";
+ self.providerAstakosAccountURLTextField = ((RSTextFieldCell *)cell).textField;
+ providerAstakosAccountURLTextField.placeholder = @"Required";
+ providerAstakosAccountURLTextField.keyboardType = UIKeyboardTypeURL;
+ providerAstakosAccountURLTextField.returnKeyType = UIReturnKeyNext;
+ providerAstakosAccountURLTextField.delegate = self;
+ }
+ providerAstakosAccountURLTextField.text = providerAstakosAccountURLString;
+ } else if (indexPath.row == kProviderAstakosWebloginURL) {
+ static NSString *CellIdentifier = @"ProviderAstakosWebloginURLCell";
+ cell = (RSTextFieldCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
+ ((RSTextFieldCell *)cell).modalPresentationStyle = UIModalPresentationFormSheet;
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.textLabel.text = @"Astakos Weblogin";
+ self.providerAstakosWebloginURLTextField = ((RSTextFieldCell *)cell).textField;
+ providerAstakosWebloginURLTextField.placeholder = @"Required";
+ providerAstakosWebloginURLTextField.keyboardType = UIKeyboardTypeURL;
+ providerAstakosWebloginURLTextField.returnKeyType = UIReturnKeyNext;
+ providerAstakosWebloginURLTextField.delegate = self;
+ }
+ providerAstakosWebloginURLTextField.text = providerAstakosWebloginURLString;
+ }
}
-
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == getTokenSection) {
- NSURL *loginURLPrefix = nil;
- if (customProvider) {
- if (!apiEndpointTextField.text || ![apiEndpointTextField.text isURL]) {
- [self alert:@"No API URL" message:@"Please enter an API Authentication URL"];
+ if (customProvider && !provider.manual && ![providerAuthURLString isURL]) {
+ [self alert:nil message:@"Please enter an Auth URL"];
+ [providerAuthURLTextField becomeFirstResponder];
+ [tableView deselectRowAtIndexPath:indexPath animated:NO];
+ } else if (customProvider && provider.manual && ![providerAstakosWebloginURLString isURL]) {
+ [self alert:nil message:@"Please enter a Weblogin URL"];
+ [providerAstakosWebloginURLTextField becomeFirstResponder];
+ [tableView deselectRowAtIndexPath:indexPath animated:NO];
+ } else {
+ if (!account) {
+ account = [[OpenStackAccount alloc] init];
+ }
+
+ if (customProvider) {
+ if (!provider.manual) {
+ provider.authURL = [NSURL URLWithString:providerAuthURLString];
+ } else {
+ provider.astakosWebloginURL = [NSURL URLWithString:providerAstakosWebloginURLString];
+ }
+ }
+ account.provider = [[provider copy] autorelease];
+ account.authToken = nil;
+ account.username = nil;
+ account.ignoreSSLErrors = ignoreSSLErrorsSwitch.on;
+
+ if (customProvider && provider.manual) {
+ NSString *protocol = [[[[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"] objectAtIndex:0] objectForKey:@"CFBundleURLSchemes"] objectAtIndex:0];
+ NSString *loginURL = [NSString stringWithFormat:@"%@?next=%@://login&force=", account.provider.loginURL, protocol];
+ [[UIApplication sharedApplication] openURL:[NSURL URLWithString:loginURL]];
+ [tableView deselectRowAtIndexPath:indexPath animated:NO];
} else {
- loginURLPrefix = [[NSURL URLWithString:apiEndpointTextField.text] URLByAppendingPathComponent:@"login"];
+ // POST <authURL>/tokens with no body to retrieve URLs or fallback to default manual provider
+ __block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Accessing service catalog..."
+ andAddToView:self.view];
+ [[account.manager serviceCatalog]
+ success:^(OpenStackRequest *request) {
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ self.providerPithosObjectStoreURLString = account.provider.pithosObjectStoreURL.description;
+ self.providerAstakosAccountURLString = account.provider.astakosAccountURL.description;
+ self.providerAstakosWebloginURLString = account.provider.astakosWebloginURL.description;
+ [self.tableView reloadData];
+ NSString *protocol = [[[[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"] objectAtIndex:0] objectForKey:@"CFBundleURLSchemes"] objectAtIndex:0];
+ NSString *loginURL = [NSString stringWithFormat:@"%@?next=%@://login&force=", account.provider.loginURL, protocol];
+ [[UIApplication sharedApplication] openURL:[NSURL URLWithString:loginURL]];
+ [tableView deselectRowAtIndexPath:indexPath animated:NO];
+ }
+ failure:^(OpenStackRequest *request) {
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ if (request.responseStatusCode == 404) {
+ self.providerPithosObjectStoreURLString = account.provider.pithosObjectStoreURL.description;
+ self.providerAstakosAccountURLString = account.provider.astakosAccountURL.description;
+ self.providerAstakosWebloginURLString = account.provider.astakosWebloginURL.description;
+ provider.manual = YES;
+ providerManualSwitch.on = YES;
+ [self.tableView reloadData];
+ NSString *protocol = [[[[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"] objectAtIndex:0] objectForKey:@"CFBundleURLSchemes"] objectAtIndex:0];
+ NSString *loginURL = [NSString stringWithFormat:@"%@?next=%@://login&force=", account.provider.loginURL, protocol];
+ [[UIApplication sharedApplication] openURL:[NSURL URLWithString:loginURL]];
+ } else {
+ [self alert:nil request:request];
+ }
+ [tableView deselectRowAtIndexPath:indexPath animated:NO];
+ }];
}
- } else {
- loginURLPrefix = provider.loginURL;
}
- NSString *protocol = [[[[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"] objectAtIndex:0] objectForKey:@"CFBundleURLSchemes"] objectAtIndex:0];
- NSString *loginURL = [NSString stringWithFormat:@"%@?next=%@://login&force=", loginURLPrefix, protocol];
- [[UIApplication sharedApplication] openURL:[NSURL URLWithString:loginURL]];
- [tableView deselectRowAtIndexPath:indexPath animated:NO];
}
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if ([textField isEqual:providerNameTextField]) {
- [apiEndpointTextField becomeFirstResponder];
- } else if ([textField isEqual:apiEndpointTextField]) {
- [usernameTextField becomeFirstResponder];
- [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:kAuthToken inSection:authenticationSection] atScrollPosition:UITableViewScrollPositionNone animated:YES];
- } else if ([textField isEqual:usernameTextField]) {
+ [providerManualSwitch.on ? providerPithosObjectStoreURLTextField : providerAuthURLTextField becomeFirstResponder];
+ [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:kProviderAuthURLOrPithosObjectStoreURL inSection:providerSection] atScrollPosition:UITableViewScrollPositionNone animated:YES];
+ } else if ([textField isEqual:providerPithosObjectStoreURLTextField]) {
+ [providerAstakosAccountURLTextField becomeFirstResponder];
+ [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:kProviderAstakosAccountURL inSection:providerSection] atScrollPosition:UITableViewScrollPositionNone animated:YES];
+ } else if ([textField isEqual:providerAstakosAccountURLTextField]) {
+ [providerAstakosWebloginURLTextField becomeFirstResponder];
+ [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:kProviderAstakosWebloginURL inSection:providerSection] atScrollPosition:UITableViewScrollPositionNone animated:YES];
+ } else if ([textField isEqual:providerAuthURLTextField] || [textField isEqual:providerAstakosWebloginURLTextField]) {
[authTokenTextField becomeFirstResponder];
- [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:kAuthToken inSection:authenticationSection] atScrollPosition:UITableViewScrollPositionNone animated:YES];
+ [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:kAuthToken inSection:authenticationSection] atScrollPosition:UITableViewScrollPositionNone animated:YES];
+ } else if ([textField isEqual:authTokenTextField] && (authTokenTextField.returnKeyType == UIReturnKeyNext)) {
+ [usernameTextField becomeFirstResponder];
+ [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:kUsername inSection:authenticationSection] atScrollPosition:UITableViewScrollPositionNone animated:YES];
} else {
[textField resignFirstResponder];
[self saveButtonPressed:self];
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *result = [textField.text stringByReplacingCharactersInRange:range withString:string];
- if ([textField isEqual:usernameTextField]) {
- self.username = result;
- } else if ([textField isEqual:authTokenTextField]) {
+ if ([textField isEqual:authTokenTextField]) {
self.authToken = result;
+ } else if ([textField isEqual:usernameTextField]) {
+ self.username = result;
+ } else if ([textField isEqual:providerNameTextField]) {
+ self.providerName = result;
+ } else if ([textField isEqual:providerAuthURLTextField]) {
+ self.providerAuthURLString = result;
+ } else if ([textField isEqual:providerPithosObjectStoreURLTextField]) {
+ self.providerPithosObjectStoreURLString = result;
+ } else if ([textField isEqual:providerAstakosAccountURLTextField]) {
+ self.providerAstakosAccountURLString = result;
+ } else if ([textField isEqual:providerAstakosWebloginURLTextField]) {
+ self.providerAstakosWebloginURLString = result;
}
return YES;
}
-#pragma mark - Actions
-
-- (void)setUsername:(NSString *)aUsername andAuthToken:(NSString *)anAuthToken {
- if (aUsername)
- self.username = aUsername;
- if (anAuthToken)
- self.authToken = anAuthToken;
-}
-
#pragma mark - Button Handlers
- (void)saveButtonPressed:(id)sender {
#pragma mark - Authentication
- (void)authenticate {
- if (customProvider && (!providerNameTextField.text || [providerNameTextField.text isEqualToString:@""])) {
- [self alert:nil message:@"Please enter a Provider Name."];
+ if (customProvider && !providerName.length) {
+ [self alert:nil message:@"Please enter a Provider Name"];
self.navigationItem.rightBarButtonItem.enabled = YES;
[providerNameTextField becomeFirstResponder];
- } else if (customProvider && (!apiEndpointTextField.text || ![apiEndpointTextField.text isURL])) {
- [self alert:nil message:@"Please enter an API Authentication URL."];
+ } else if (customProvider && !provider.manual && ![providerAuthURLString isURL]) {
+ [self alert:nil message:@"Please enter an Auth URL"];
self.navigationItem.rightBarButtonItem.enabled = YES;
- [apiEndpointTextField becomeFirstResponder];
- } else if (!usernameTextField.text || [usernameTextField.text isEqualToString:@""]) {
- [self alert:nil message:@"Please enter your UUID."];
+ [providerAuthURLTextField becomeFirstResponder];
+ } else if (customProvider && provider.manual && ![providerPithosObjectStoreURLString isURL]) {
+ [self alert:nil message:@"Please enter a Pithos URL"];
self.navigationItem.rightBarButtonItem.enabled = YES;
- [usernameTextField becomeFirstResponder];
+ [providerPithosObjectStoreURLTextField becomeFirstResponder];
+ } else if (customProvider && provider.manual && ![providerAstakosAccountURLString isURL]) {
+ [self alert:nil message:@"Please enter an Astakos URL"];
+ self.navigationItem.rightBarButtonItem.enabled = YES;
+ [providerAstakosAccountURLTextField becomeFirstResponder];
+ } else if (customProvider && provider.manual && ![providerAstakosWebloginURLString isURL]) {
+ [self alert:nil message:@"Please enter a Weblogin URL"];
+ self.navigationItem.rightBarButtonItem.enabled = YES;
+ [providerAstakosWebloginURLTextField becomeFirstResponder];
} else if (!authTokenTextField.text || [authTokenTextField.text isEqualToString:@""]) {
- [self alert:nil message:@"Please enter your Token."];
+ [self alert:nil message:@"Please enter your Token"];
self.navigationItem.rightBarButtonItem.enabled = YES;
[authTokenTextField becomeFirstResponder];
+ } else if (provider.manual && (!usernameTextField.text || [usernameTextField.text isEqualToString:@""])) {
+ [self alert:nil message:@"Please enter your UUID"];
+ self.navigationItem.rightBarButtonItem.enabled = YES;
+ [usernameTextField becomeFirstResponder];
} else {
- account = [[OpenStackAccount alloc] init];
+ if (!account) {
+ account = [[OpenStackAccount alloc] init];
+ }
+
if (customProvider) {
- account.provider = [[[Provider alloc] init] autorelease];
- account.provider.name = providerNameTextField.text;
- account.provider.hostURL = [NSURL URLWithString:apiEndpointTextField.text];
- account.provider.version = @"v1";
- } else {
- account.provider = provider;
+ if (!provider.manual) {
+ provider.authURL = [NSURL URLWithString:providerAuthURLString];
+ } else {
+ provider.pithosObjectStoreURL = [NSURL URLWithString:providerPithosObjectStoreURLString];
+ provider.astakosAccountURL = [NSURL URLWithString:providerAstakosAccountURLString];
+ provider.astakosWebloginURL = [NSURL URLWithString:providerAstakosWebloginURLString];
+ }
}
- account.username = usernameTextField.text;
+ account.provider = [[provider copy] autorelease];
account.authToken = authTokenTextField.text;
-
+ account.username = usernameTextField.text;
+ account.ignoreSSLErrors = ignoreSSLErrorsSwitch.on;
+
__block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Authenticating..."
andAddToView:self.view];
- [[account.manager authenticate]
- success:^(OpenStackRequest *request) {
- if ([request isSuccess]) {
- NSString *storageURLString = [[request responseHeaders] objectForKey:@"X-Storage-Url"];
- if (storageURLString) {
- account.filesURL = [NSURL URLWithString:storageURLString];
+ if (provider.manual) {
+ [[account.manager authenticate]
+ success:^(OpenStackRequest *request) {
+ if ([request isSuccess]) {
+ NSString *storageURLString = [[request responseHeaders] objectForKey:@"X-Storage-Url"];
+ if (storageURLString) {
+ account.filesURL = [NSURL URLWithString:storageURLString];
+ } else {
+ account.filesURL = [account.provider.authEndpointURL URLByAppendingPathComponent:account.username];
+ }
+ [account persist];
+ [[account.manager userCatalogForDisplaynames:nil UUIDs:[NSArray arrayWithObject:account.username]]
+ success:^(OpenStackRequest *request) {
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ [rootViewController.tableView reloadData];
+ [self.navigationController dismissModalViewControllerAnimated:YES];
+ }
+ failure:^(OpenStackRequest *request) {
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ [rootViewController.tableView reloadData];
+ [self.navigationController dismissModalViewControllerAnimated:YES];
+ }];
+ } else {
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ self.navigationItem.rightBarButtonItem.enabled = YES;
+ [self alert:@"Authentication Failure" message:@"Please check your Token and UUID."];
+ }
+ }
+ failure:^(OpenStackRequest *request) {
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ self.navigationItem.rightBarButtonItem.enabled = YES;
+ if ([request responseStatusCode] == 401) {
+ [self alert:@"Authentication Failure" message:@"Please check your Token and UUID."];
} else {
+ [self alert:nil request:request];
+ }
+ }];
+ } else {
+ [[account.manager serviceCatalog]
+ success:^(OpenStackRequest *request) {
+ if ([request isSuccess]) {
account.filesURL = [account.provider.authEndpointURL URLByAppendingPathComponent:account.username];
+ [account persist];
+ [[account.manager userCatalogForDisplaynames:nil UUIDs:[NSArray arrayWithObject:account.username]]
+ success:^(OpenStackRequest *request) {
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ [rootViewController.tableView reloadData];
+ [self.navigationController dismissModalViewControllerAnimated:YES];
+ }
+ failure:^(OpenStackRequest *request) {
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ [rootViewController.tableView reloadData];
+ [self.navigationController dismissModalViewControllerAnimated:YES];
+ }];
+ } else {
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ self.navigationItem.rightBarButtonItem.enabled = YES;
+ [self alert:@"Authentication Failure" message:@"Please check your Token."];
}
- [account persist];
- [[account.manager userCatalogForDisplaynames:nil UUIDs:[NSArray arrayWithObject:account.username]]
- success:^(OpenStackRequest *request) {
- [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
- [rootViewController.tableView reloadData];
- [self.navigationController dismissModalViewControllerAnimated:YES];
- }
- failure:^(OpenStackRequest *request) {
- [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
- [rootViewController.tableView reloadData];
- [self.navigationController dismissModalViewControllerAnimated:YES];
- }];
- } else {
- [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
- self.navigationItem.rightBarButtonItem.enabled = YES;
- [self alert:@"Authentication Failure" message:@"Please check your UUID and Token."];
- }
- }
- failure:^(OpenStackRequest *request) {
- [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
- self.navigationItem.rightBarButtonItem.enabled = YES;
- if ([request responseStatusCode] == 401) {
- [self alert:@"Authentication Failure" message:@"Please check your UUID and Token."];
- } else {
- [self failOnBadConnection];
}
- }];
+ failure:^(OpenStackRequest *request) {
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ self.navigationItem.rightBarButtonItem.enabled = YES;
+ if (request.responseStatusCode == 404) {
+ self.providerPithosObjectStoreURLString = account.provider.pithosObjectStoreURL.description;
+ self.providerAstakosAccountURLString = account.provider.astakosAccountURL.description;
+ self.providerAstakosWebloginURLString = account.provider.astakosWebloginURL.description;
+ provider.manual = YES;
+ providerManualSwitch.on = YES;
+ [self.tableView reloadData];
+ [self alert:@"Authentication Failure" message:@"Please enter also your UUID."];
+ } else if ([request responseStatusCode] == 401) {
+ [self alert:@"Authentication Failure" message:@"Please check your Token."];
+ } else {
+ [self alert:nil request:request];
+ }
+ }];
+ }
}
}
@property (nonatomic, assign) OpenStackAccount *account;
@property (nonatomic, retain) ASINetworkQueue *queue;
+- (APICallback *)serviceCatalog;
+
- (APICallback *)userCatalogForDisplaynames:(NSArray *)displaynames UUIDs:(NSArray *)UUIDs;
- (APICallback *)authenticate;
}
#pragma mark - API Calls
+#pragma mark Service Catalog
+
+- (APICallback *)serviceCatalog {
+ __block OpenStackRequest *request = [OpenStackRequest serviceCatalogRequest:self.account];
+ return [self callbackWithRequest:request success:^(OpenStackRequest *request) {
+ NSURL *pithosObjectStoreURL = nil;
+ NSURL *astakosAccountURL = nil;
+ NSURL *astakosWebloginURL = nil;
+ NSArray *serviceCatalog = [request serviceCatalog];
+ for (NSDictionary *service in serviceCatalog) {
+ NSString *serviceName = [service objectForKey:@"name"];
+ if (!pithosObjectStoreURL && [serviceName isEqualToString:@"pithos_object-store"]) {
+ pithosObjectStoreURL = [NSURL URLWithString:[[[service objectForKey:@"endpoints"]
+ objectAtIndex:0]
+ objectForKey:@"publicURL"]];
+ } else if (!astakosAccountURL && [serviceName isEqualToString:@"astakos_account"]) {
+ astakosAccountURL = [NSURL URLWithString:[[[service objectForKey:@"endpoints"]
+ objectAtIndex:0]
+ objectForKey:@"publicURL"]];
+ } else if (!astakosWebloginURL && [serviceName isEqualToString:@"astakos_weblogin"]) {
+ astakosWebloginURL = [NSURL URLWithString:[[[service objectForKey:@"endpoints"]
+ objectAtIndex:0]
+ objectForKey:@"SNF:webloginURL"]];
+ }
+ if (pithosObjectStoreURL && astakosAccountURL && astakosWebloginURL)
+ break;
+ }
+ self.account.provider.pithosObjectStoreURL = pithosObjectStoreURL;
+ self.account.provider.astakosAccountURL = astakosAccountURL;
+ self.account.provider.astakosWebloginURL = astakosWebloginURL;
+ self.account.provider.manual = NO;
+
+ if (self.account.authToken.length) {
+ NSDictionary *token = [request token];
+ self.account.authToken = [token objectForKey:@"id"];
+ self.account.username = [[token objectForKey:@"tenant"] objectForKey:@"id"];
+ }
+ } failure:^(OpenStackRequest *request) {
+ if (request.responseStatusCode == 404) {
+ self.account.provider.pithosObjectStoreURL = [self.account.provider.authURL URLByAppendingPathComponent:@"v1"];
+ self.account.provider.astakosAccountURL = [[self.account.provider.authURL copy] autorelease];
+ self.account.provider.astakosWebloginURL = [[self.account.provider.authURL copy] autorelease];
+ self.account.provider.manual = YES;
+ }
+ }];
+}
+
#pragma mark User Catalog
- (APICallback *)userCatalogForDisplaynames:(NSArray *)displaynames UUIDs:(NSArray *)UUIDs {
// The OpenStack project is provided under the Apache 2.0 license.
//
-@class OpenStackAccount;
+@class OpenStackAccount, Provider;
@interface AccountSettingsViewController : UITableViewController <UITextFieldDelegate> {
- UITextField *usernameTextField;
+ UITextField *providerAuthURLTextField;
+ UITextField *providerPithosObjectStoreURLTextField;
+ UITextField *providerAstakosAccountURLTextField;
+ UITextField *providerAstakosWebloginURLTextField;
+ UISwitch *providerManualSwitch;
+
UITextField *authTokenTextField;
+ UITextField *usernameTextField;
+ UITextField *displaynameTextField;
+
+ UISwitch *ignoreSSLErrorsSwitch;
- NSInteger userDetailsSection;
+ NSInteger providerSection;
+ NSInteger authenticationSection;
NSInteger getTokenSection;
+ NSInteger optionsSection;
+
+ OpenStackAccount *account;
+ Provider *provider;
+
+ NSString *providerAuthURLString;
+ NSString *providerPithosObjectStoreURLString;
+ NSString *providerAstakosAccountURLString;
+ NSString *providerAstakosWebloginURLString;
NSString *username;
NSString *authToken;
NSString *displayname;
+
+ UIColor *editColor;
}
@property (nonatomic, retain) OpenStackAccount *account;
@property (nonatomic, retain) NSString *username;
@property (nonatomic, retain) NSString *authToken;
-@property (nonatomic, retain) NSString *displayname;
-- (void)setUsername:(NSString *)aUsername andAuthToken:(NSString *)anAuthToken;
- (void)saveButtonPressed:(id)sender;
@end
#import "OpenStackAppDelegate.h"
#import "UIViewController+Conveniences.h"
#import "OpenStackRequest.h"
+#import "NSString+Conveniences.h"
-#define kUsername 0
-#define kAuthToken 1
+#define kProviderManualSwitch 0
+#define kProviderPithosObjectStoreURL 1
+#define kProviderAstakosAccountURL 2
+#define kProviderAstakosWebloginURL 3
+#define kProviderAuthURL 4
+
+#define kAuthToken 0
+#define kUsername 1
#define kDisplayname 2
+#define kIgnoreSSLErrorsSwitch 0
+
+@interface AccountSettingsViewController()
+@property (nonatomic, retain) Provider *provider;
+@property (nonatomic, retain) UITextField *providerAuthURLTextField;
+@property (nonatomic, retain) UITextField *providerPithosObjectStoreURLTextField;
+@property (nonatomic, retain) UITextField *providerAstakosAccountURLTextField;
+@property (nonatomic, retain) UITextField *providerAstakosWebloginURLTextField;
+
+@property (nonatomic, retain) UITextField *authTokenTextField;
+@property (nonatomic, retain) UITextField *usernameTextField;
+@property (nonatomic, retain) UITextField *displaynameTextField;
+
+@property (nonatomic, retain) NSString *providerAuthURLString;
+@property (nonatomic, retain) NSString *providerPithosObjectStoreURLString;
+@property (nonatomic, retain) NSString *providerAstakosAccountURLString;
+@property (nonatomic, retain) NSString *providerAstakosWebloginURLString;
+
+@property (nonatomic, retain) NSString *displayname;
+
+@property (nonatomic, retain) UIColor *editColor;
+@end
+
@implementation AccountSettingsViewController
-@synthesize account, username, authToken, displayname;
+@synthesize account, username, authToken;
+@synthesize provider, providerAuthURLTextField, providerPithosObjectStoreURLTextField, providerAstakosAccountURLTextField,
+ providerAstakosWebloginURLTextField;
+@synthesize authTokenTextField, usernameTextField, displaynameTextField;
+@synthesize providerAuthURLString, providerPithosObjectStoreURLString, providerAstakosAccountURLString, providerAstakosWebloginURLString;
+@synthesize displayname, editColor;
#pragma mark - View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = @"Authentication";
- userDetailsSection = 0;
- getTokenSection = 1;
+ providerSection = 0;
+ authenticationSection = 1;
+ getTokenSection = 2;
+ optionsSection = 3;
displayname = [[self.account displaynameForUUID:self.account.username safe:NO] retain];
[self addSaveButton];
- self.navigationItem.rightBarButtonItem.enabled = NO;
+
+ providerManualSwitch = [[UISwitch alloc] init];
+ [providerManualSwitch addTarget:self action:@selector(providerManualSwitchChanged:) forControlEvents:UIControlEventValueChanged];
+
+ ignoreSSLErrorsSwitch = [[UISwitch alloc] init];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+ self.provider = [[account.provider copy] autorelease];
+ self.providerAuthURLString = provider.authURL.description;
+ self.providerPithosObjectStoreURLString = provider.pithosObjectStoreURL.description;
+ self.providerAstakosAccountURLString = provider.astakosAccountURL.description;
+ self.providerAstakosWebloginURLString = provider.astakosWebloginURL.description;
+ providerManualSwitch.on = provider.manual;
+ self.authToken = account.authToken;
+ self.username = account.username;
+ ignoreSSLErrorsSwitch.on = account.ignoreSSLErrors;
+ [super viewWillAppear:animated];
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+ [super viewWillDisappear:animated];
+ [providerAuthURLTextField resignFirstResponder];
+ [providerPithosObjectStoreURLTextField resignFirstResponder];
+ [providerAstakosAccountURLTextField resignFirstResponder];
+ [providerAstakosWebloginURLTextField resignFirstResponder];
+ [usernameTextField resignFirstResponder];
+ [authTokenTextField resignFirstResponder];
}
#pragma mark - Memory management
- (void)dealloc {
- [username release];
+ [account release];
+ [provider release];
+ [providerAuthURLTextField release];
+ [providerPithosObjectStoreURLTextField release];
+ [providerAstakosAccountURLTextField release];
+ [providerAstakosWebloginURLTextField release];
+ [providerManualSwitch release];
+ [authTokenTextField release];
+ [usernameTextField release];
+ [ignoreSSLErrorsSwitch release];
+ [providerAuthURLString release];
+ [providerPithosObjectStoreURLString release];
+ [providerAstakosAccountURLString release];
+ [providerAstakosWebloginURLString release];
[authToken release];
+ [username release];
[displayname release];
- [account release];
+ [editColor release];
[super dealloc];
}
#pragma mark - Internal
-- (void) updateSaveButtonForUsername:(NSString *)checkUsername andAuthToken:(NSString *)checkAuthToken {
- self.navigationItem.rightBarButtonItem.enabled = (checkUsername && checkUsername.length &&
- checkAuthToken && checkAuthToken.length &&
- (![checkUsername isEqualToString:account.username] ||
- ![checkAuthToken isEqualToString:account.authToken]));
+- (void)providerManualSwitchChanged:(id)sender {
+ provider.manual = providerManualSwitch.on;
+ [self.tableView reloadData];
}
#pragma mark - Properties
[username release];
username = [aUsername retain];
self.displayname = [self.account displaynameForUUID:username safe:NO];
- [self updateSaveButtonForUsername:username andAuthToken:authTokenTextField.text];
-}
-
-- (void)setAuthToken:(NSString *)anAuthToken {
- [authToken release];
- authToken = [anAuthToken retain];
- [self updateSaveButtonForUsername:usernameTextField.text andAuthToken:authToken];
}
- (void)setDisplayname:(NSString *)aDisplayname {
[displayname release];
displayname = [aDisplayname retain];
if (reloadDisplayname) {
- [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:kDisplayname inSection:userDetailsSection]]
+ [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:kDisplayname inSection:authenticationSection]]
withRowAnimation:UITableViewRowAnimationNone];
}
}
-#pragma mark - Actions
-
-- (void)setUsername:(NSString *)aUsername andAuthToken:(NSString *)anAuthToken {
- if (aUsername) {
- [username release];
- username = [aUsername retain];
- self.displayname = [self.account displaynameForUUID:username safe:NO];
- }
- if (anAuthToken) {
- [authToken release];
- authToken = [anAuthToken retain];
- }
- [self updateSaveButtonForUsername:username andAuthToken:authToken];
-}
-
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
- return 2;
+ return 4;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
- if (section == userDetailsSection)
+ if (section == providerSection) {
+ return (provider.manual ? 4 : 5);
+ } else if (section == authenticationSection) {
return 3;
- else
+ } else {
return 1;
+ }
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
- if (section == userDetailsSection)
- return [NSString stringWithFormat:@"%@ Login", self.account.provider.name];
- else
- return nil;
-}
-
-- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section {
- if (section == userDetailsSection)
- return @"API Version 1.0";
- else
+ if (section == providerSection) {
+ return [NSString stringWithFormat:@"%@ Provider Details", self.account.provider.name];
+ } else if (section == authenticationSection) {
+ return @"Login";
+ } else if (section == optionsSection) {
+ return @"Options";
+ } else {
return nil;
+ }
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
- static NSString *CellIdentifier = @"Cell";
- RSTextFieldCell *cell = nil;
- if (indexPath.section == userDetailsSection) {
- cell = (RSTextFieldCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
- if (cell == nil) {
- cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
- cell.selectionStyle = UITableViewCellSelectionStyleNone;
- }
-
- if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
- cell.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.8];
+ UITableViewCell *cell = nil;
+ if (indexPath.section == providerSection) {
+ if (indexPath.row == kProviderManualSwitch) {
+ static NSString *CellIdentifier = @"SwitchCell";
+ cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ }
+ cell.textLabel.text = @"Manual";
+ cell.accessoryView = providerManualSwitch;
+ } else if (indexPath.row == kProviderPithosObjectStoreURL) {
+ static NSString *CellIdentifier = @"ProviderPithosObjectStoreURLCell";
+ cell = (RSTextFieldCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.textLabel.text = @"Pithos URL";
+ self.providerPithosObjectStoreURLTextField = ((RSTextFieldCell *)cell).textField;
+ providerPithosObjectStoreURLTextField.keyboardType = UIKeyboardTypeURL;
+ providerPithosObjectStoreURLTextField.returnKeyType = UIReturnKeyNext;
+ if (!editColor)
+ self.editColor = providerPithosObjectStoreURLTextField.textColor;
+ }
+ if (provider.manual) {
+ cell.userInteractionEnabled = YES;
+ providerPithosObjectStoreURLTextField.textColor = editColor;
+ providerPithosObjectStoreURLTextField.placeholder = @"Required";
+ providerPithosObjectStoreURLTextField.delegate = self;
+ } else {
+ cell.userInteractionEnabled = NO;
+ providerPithosObjectStoreURLTextField.textColor = [UIColor grayColor];
+ providerPithosObjectStoreURLTextField.placeholder = @"Fetched on save";
+ providerPithosObjectStoreURLTextField.delegate = nil;
+ }
+ providerPithosObjectStoreURLTextField.text = providerPithosObjectStoreURLString;
+ } else if (indexPath.row == kProviderAstakosAccountURL) {
+ static NSString *CellIdentifier = @"ProviderAstakosAccountURLCell";
+ cell = (RSTextFieldCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.textLabel.text = @"Astakos URL";
+ self.providerAstakosAccountURLTextField = ((RSTextFieldCell *)cell).textField;
+ providerAstakosAccountURLTextField.keyboardType = UIKeyboardTypeURL;
+ providerAstakosAccountURLTextField.returnKeyType = UIReturnKeyNext;
+ }
+ if (provider.manual) {
+ cell.userInteractionEnabled = YES;
+ providerAstakosAccountURLTextField.textColor = editColor;
+ providerAstakosAccountURLTextField.placeholder = @"Required";
+ providerAstakosAccountURLTextField.delegate = self;
+ } else {
+ cell.userInteractionEnabled = NO;
+ providerAstakosAccountURLTextField.textColor = [UIColor grayColor];
+ providerAstakosAccountURLTextField.placeholder = @"Fetched on save";
+ providerAstakosAccountURLTextField.delegate = nil;
+ }
+ providerAstakosAccountURLTextField.text = providerAstakosAccountURLString;
+ } else if (indexPath.row == kProviderAstakosWebloginURL) {
+ static NSString *CellIdentifier = @"ProviderAstakosWebloginURLCell";
+ cell = (RSTextFieldCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.textLabel.text = @"Weblogin URL";
+ self.providerAstakosWebloginURLTextField = ((RSTextFieldCell *)cell).textField;
+ providerAstakosWebloginURLTextField.keyboardType = UIKeyboardTypeURL;
+ providerAstakosWebloginURLTextField.returnKeyType = UIReturnKeyNext;
+ }
+ if (provider.manual) {
+ cell.userInteractionEnabled = YES;
+ providerAstakosWebloginURLTextField.textColor = editColor;
+ providerAstakosWebloginURLTextField.placeholder = @"Required";
+ providerAstakosWebloginURLTextField.delegate = self;
+ } else {
+ cell.userInteractionEnabled = NO;
+ providerAstakosWebloginURLTextField.textColor = [UIColor grayColor];
+ providerAstakosWebloginURLTextField.placeholder = @"Fetched on save";
+ providerAstakosWebloginURLTextField.delegate = nil;
+ }
+ providerAstakosWebloginURLTextField.text = providerAstakosWebloginURLString;
+ } else if (indexPath.row == kProviderAuthURL) {
+ static NSString *CellIdentifier = @"ProviderAuthURLCell";
+ cell = (RSTextFieldCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.textLabel.text = @"Auth URL";
+ self.providerAuthURLTextField = ((RSTextFieldCell *)cell).textField;
+ providerAuthURLTextField.placeholder = @"Required";
+ providerAuthURLTextField.keyboardType = UIKeyboardTypeURL;
+ providerAuthURLTextField.returnKeyType = UIReturnKeyNext;
+ providerAstakosWebloginURLTextField.delegate = self;
+ }
+ providerAuthURLTextField.text = providerAuthURLString;
}
-
- [cell.textLabel setBackgroundColor:[UIColor clearColor]];
-
- if (indexPath.row == kUsername) {
- cell.textLabel.text = @"UUID";
- cell.userInteractionEnabled = YES;
- cell.textField.delegate = self;
- cell.textField.returnKeyType = UIReturnKeyNext;
- cell.textField.text = (username ? username : self.account.username);
- usernameTextField = cell.textField;
- } else if (indexPath.row == kAuthToken) {
- cell.textLabel.text = @"Token";
- cell.userInteractionEnabled = YES;
- cell.textField.delegate = self;
- cell.textField.returnKeyType = UIReturnKeyDone;
- cell.textField.text = (authToken ? authToken : self.account.authToken);
- authTokenTextField = cell.textField;
+ } else if (indexPath.section == authenticationSection) {
+ if (indexPath.row == kAuthToken) {
+ static NSString *CellIdentifier = @"AuthTokenCell";
+ cell = (RSTextFieldCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.textLabel.text = @"Token";
+ self.authTokenTextField = ((RSTextFieldCell *)cell).textField;
+ authTokenTextField.placeholder = @"Input or retrieve";
+ authTokenTextField.delegate = self;
+ }
+ authTokenTextField.returnKeyType = (provider.manual ? UIReturnKeyNext : UIReturnKeyDone);
+ authTokenTextField.text = authToken;
+ } else if (indexPath.row == kUsername) {
+ static NSString *CellIdentifier = @"UsernameCell";
+ cell = (RSTextFieldCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.textLabel.text = @"UUID";
+ self.usernameTextField = ((RSTextFieldCell *)cell).textField;
+ usernameTextField.returnKeyType = UIReturnKeyDone;
+ }
+ if (provider.manual) {
+ cell.userInteractionEnabled = YES;
+ usernameTextField.textColor = editColor;
+ usernameTextField.placeholder = @"Input or retrieve";
+ usernameTextField.delegate = self;
+ } else {
+ cell.userInteractionEnabled = NO;
+ usernameTextField.textColor = [UIColor grayColor];
+ usernameTextField.placeholder = @"Fetched on save";
+ usernameTextField.delegate = nil;
+ }
+ usernameTextField.text = username;
} else if (indexPath.row == kDisplayname) {
- cell.textLabel.text = @"User";
- cell.userInteractionEnabled = NO;
- cell.textField.textColor = [UIColor grayColor];
- cell.textField.delegate = nil;
- cell.textField.text = displayname;
+ static NSString *CellIdentifier = @"DisplaynameCell";
+ cell = (RSTextFieldCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.textLabel.text = @"User";
+ cell.userInteractionEnabled = NO;
+ self.displaynameTextField = ((RSTextFieldCell *)cell).textField;
+ displaynameTextField.textColor = [UIColor grayColor];
+ }
+ displaynameTextField.text = displayname;
}
- } else {
- cell = (RSTextFieldCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
- if (cell == nil) {
- cell = [[[RSTextFieldCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
+ } else if (indexPath.section == getTokenSection) {
+ static NSString *CellIdentifier = @"Cell";
+ cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
+ }
+ cell.textLabel.textAlignment = UITextAlignmentCenter;
+ cell.textLabel.text = @"Retrieve Token";
+ } else if (indexPath.section == optionsSection) {
+ if (indexPath.row == kIgnoreSSLErrorsSwitch) {
+ static NSString *CellIdentifier = @"SwitchCell";
+ cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if (!cell) {
+ cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ }
+ cell.textLabel.text = @"Ignore SSL Errors";
+ cell.accessoryView = ignoreSSLErrorsSwitch;
}
-
- cell.textLabel.text = @"Get Token";
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.section == getTokenSection) {
- NSString *protocol = [[[[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"] objectAtIndex:0] objectForKey:@"CFBundleURLSchemes"] objectAtIndex:0];
- NSString *loginURL = [NSString stringWithFormat:@"%@?next=%@://login&force=", account.provider.loginURL, protocol];
- [[UIApplication sharedApplication] openURL:[NSURL URLWithString:loginURL]];
- [tableView deselectRowAtIndexPath:indexPath animated:NO];
+ if (!provider.manual && ![providerAuthURLString isURL]) {
+ [self alert:nil message:@"Please enter an Auth URL"];
+ [providerAuthURLTextField becomeFirstResponder];
+ [tableView deselectRowAtIndexPath:indexPath animated:NO];
+ } else if (provider.manual && ![providerAstakosWebloginURLString isURL]) {
+ [self alert:nil message:@"Please enter a Weblogin URL"];
+ [providerAstakosWebloginURLTextField becomeFirstResponder];
+ [tableView deselectRowAtIndexPath:indexPath animated:NO];
+ } else {
+ if (!provider.manual) {
+ provider.authURL = [NSURL URLWithString:providerAuthURLString];
+ } else {
+ provider.astakosWebloginURL = [NSURL URLWithString:providerAstakosWebloginURLString];
+ }
+ OpenStackAccount *temporaryAccount = [[[OpenStackAccount alloc] init] autorelease];
+ temporaryAccount.provider = [[provider copy] autorelease];
+ temporaryAccount.username = nil;
+ temporaryAccount.authToken = nil;
+ temporaryAccount.ignoreSSLErrors = ignoreSSLErrorsSwitch.on;
+
+ if (provider.manual) {
+ NSString *protocol = [[[[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"] objectAtIndex:0] objectForKey:@"CFBundleURLSchemes"] objectAtIndex:0];
+ NSString *loginURL = [NSString stringWithFormat:@"%@?next=%@://login&force=", temporaryAccount.provider.loginURL, protocol];
+ [[UIApplication sharedApplication] openURL:[NSURL URLWithString:loginURL]];
+ [tableView deselectRowAtIndexPath:indexPath animated:NO];
+ } else {
+ // POST <authURL>/tokens with no body to retrieve URLs or fallback to default manual provider
+ __block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Accessing service catalog..."
+ andAddToView:self.view];
+ [[temporaryAccount.manager serviceCatalog]
+ success:^(OpenStackRequest *request) {
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ self.providerPithosObjectStoreURLString = request.account.provider.pithosObjectStoreURL.description;
+ self.providerAstakosAccountURLString = request.account.provider.astakosAccountURL.description;
+ self.providerAstakosWebloginURLString = request.account.provider.astakosWebloginURL.description;
+ [self.tableView reloadData];
+ NSString *protocol = [[[[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"] objectAtIndex:0] objectForKey:@"CFBundleURLSchemes"] objectAtIndex:0];
+ NSString *loginURL = [NSString stringWithFormat:@"%@?next=%@://login&force=", request.account.provider.loginURL, protocol];
+ [[UIApplication sharedApplication] openURL:[NSURL URLWithString:loginURL]];
+ [tableView deselectRowAtIndexPath:indexPath animated:NO];
+ }
+ failure:^(OpenStackRequest *request) {
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ if (request.responseStatusCode == 404) {
+ self.providerPithosObjectStoreURLString = request.account.provider.pithosObjectStoreURL.description;
+ self.providerAstakosAccountURLString = request.account.provider.astakosAccountURL.description;
+ self.providerAstakosWebloginURLString = request.account.provider.astakosWebloginURL.description;
+ provider.manual = YES;
+ providerManualSwitch.on = YES;
+ [self.tableView reloadData];
+ NSString *protocol = [[[[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"] objectAtIndex:0] objectForKey:@"CFBundleURLSchemes"] objectAtIndex:0];
+ NSString *loginURL = [NSString stringWithFormat:@"%@?next=%@://login&force=", request.account.provider.loginURL, protocol];
+ [[UIApplication sharedApplication] openURL:[NSURL URLWithString:loginURL]];
+ } else {
+ [self alert:nil request:request];
+ }
+ [tableView deselectRowAtIndexPath:indexPath animated:NO];
+ }];
+ }
+ }
}
}
#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
- [textField resignFirstResponder];
- if ([textField isEqual:usernameTextField]) {
+ if ([textField isEqual:providerPithosObjectStoreURLTextField]) {
+ [providerAstakosAccountURLTextField becomeFirstResponder];
+ [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:kProviderAstakosAccountURL inSection:providerSection] atScrollPosition:UITableViewScrollPositionNone animated:YES];
+ } else if ([textField isEqual:providerAstakosAccountURLTextField]) {
+ [providerAstakosWebloginURLTextField becomeFirstResponder];
+ [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:kProviderAstakosWebloginURL inSection:providerSection] atScrollPosition:UITableViewScrollPositionNone animated:YES];
+ } else if ([textField isEqual:providerAuthURLTextField] || [textField isEqual:providerAstakosWebloginURLTextField]) {
[authTokenTextField becomeFirstResponder];
+ [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:kAuthToken inSection:authenticationSection] atScrollPosition:UITableViewScrollPositionNone animated:YES];
+ } else if ([textField isEqual:authTokenTextField] && (authTokenTextField.returnKeyType == UIReturnKeyNext)) {
+ [usernameTextField becomeFirstResponder];
+ [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:kUsername inSection:authenticationSection] atScrollPosition:UITableViewScrollPositionNone animated:YES];
+ } else {
+ [textField resignFirstResponder];
}
return NO;
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *result = [textField.text stringByReplacingCharactersInRange:range withString:string];
- if ([textField isEqual:usernameTextField]) {
- self.username = result;
- } else if ([textField isEqual:authTokenTextField]) {
+ if ([textField isEqual:authTokenTextField]) {
self.authToken = result;
+ } else if ([textField isEqual:usernameTextField]) {
+ self.username = result;
+ } else if ([textField isEqual:providerAuthURLTextField]) {
+ self.providerAuthURLString = result;
+ } else if ([textField isEqual:providerPithosObjectStoreURLTextField]) {
+ self.providerPithosObjectStoreURLString = result;
+ } else if ([textField isEqual:providerAstakosAccountURLTextField]) {
+ self.providerAstakosAccountURLString = result;
+ } else if ([textField isEqual:providerAstakosWebloginURLTextField]) {
+ self.providerAstakosWebloginURLString = result;
}
return YES;
}
#pragma mark - Authentication
- (void)authenticate {
- if (!usernameTextField.text || [usernameTextField.text isEqualToString:@""]) {
- [self alert:nil message:@"Please enter your UUID."];
+ if (!provider.manual && ![providerAuthURLString isURL]) {
+ [self alert:nil message:@"Please enter an Auth URL"];
self.navigationItem.rightBarButtonItem.enabled = YES;
- [usernameTextField becomeFirstResponder];
+ [providerAuthURLTextField becomeFirstResponder];
+ } else if (provider.manual && ![providerPithosObjectStoreURLString isURL]) {
+ [self alert:nil message:@"Please enter a Pithos URL"];
+ self.navigationItem.rightBarButtonItem.enabled = YES;
+ [providerPithosObjectStoreURLTextField becomeFirstResponder];
+ } else if (provider.manual && ![providerAstakosAccountURLString isURL]) {
+ [self alert:nil message:@"Please enter an Astakos URL"];
+ self.navigationItem.rightBarButtonItem.enabled = YES;
+ [providerAstakosAccountURLTextField becomeFirstResponder];
+ } else if (provider.manual && ![providerAstakosWebloginURLString isURL]) {
+ [self alert:nil message:@"Please enter a Weblogin URL"];
+ self.navigationItem.rightBarButtonItem.enabled = YES;
+ [providerAstakosWebloginURLTextField becomeFirstResponder];
} else if (!authTokenTextField.text || [authTokenTextField.text isEqualToString:@""]) {
- [self alert:nil message:@"Please enter your Token."];
+ [self alert:nil message:@"Please enter your Token"];
self.navigationItem.rightBarButtonItem.enabled = YES;
[authTokenTextField becomeFirstResponder];
+ } else if (provider.manual && (!usernameTextField.text || [usernameTextField.text isEqualToString:@""])) {
+ [self alert:nil message:@"Please enter your UUID"];
+ self.navigationItem.rightBarButtonItem.enabled = YES;
+ [usernameTextField becomeFirstResponder];
} else {
+ if (!provider.manual) {
+ provider.authURL = [NSURL URLWithString:providerAuthURLString];
+ } else {
+ provider.pithosObjectStoreURL = [NSURL URLWithString:providerPithosObjectStoreURLString];
+ provider.astakosAccountURL = [NSURL URLWithString:providerAstakosAccountURLString];
+ provider.astakosWebloginURL = [NSURL URLWithString:providerAstakosWebloginURLString];
+ }
OpenStackAccount *temporaryAccount = [[[OpenStackAccount alloc] init] autorelease];
- temporaryAccount.provider = account.provider;
- temporaryAccount.username = usernameTextField.text;
+ temporaryAccount.provider = [[provider copy] autorelease];
temporaryAccount.authToken = authTokenTextField.text;
+ temporaryAccount.username = usernameTextField.text;
+ temporaryAccount.ignoreSSLErrors = ignoreSSLErrorsSwitch.on;
__block ActivityIndicatorView *activityIndicatorView = [ActivityIndicatorView activityIndicatorViewWithText:@"Authenticating..."
andAddToView:self.view];
- [[temporaryAccount.manager authenticate]
- success:^(OpenStackRequest *request) {
- if ([request isSuccess]) {
- account.username = request.account.username;
- account.authToken = request.account.authToken;
- NSString *storageURLString = [[request responseHeaders] objectForKey:@"X-Storage-Url"];
- if (storageURLString) {
- account.filesURL = [NSURL URLWithString:storageURLString];
+ if (provider.manual) {
+ [[temporaryAccount.manager authenticate]
+ success:^(OpenStackRequest *request) {
+ if ([request isSuccess]) {
+ account.provider = request.account.provider;
+ self.provider = [[account.provider copy] autorelease];
+ account.authToken = request.account.authToken;
+ account.username = request.account.username;
+ account.ignoreSSLErrors = request.account.ignoreSSLErrors;
+ NSString *storageURLString = [[request responseHeaders] objectForKey:@"X-Storage-Url"];
+ if (storageURLString) {
+ account.filesURL = [NSURL URLWithString:storageURLString];
+ } else {
+ account.filesURL = [account.provider.authEndpointURL URLByAppendingPathComponent:account.username];
+ }
+ [account persist];
+ [[account.manager userCatalogForDisplaynames:nil
+ UUIDs:[NSArray arrayWithObject:account.username]]
+ success:^(OpenStackRequest *request) {
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ self.navigationItem.rightBarButtonItem.enabled = YES;
+ self.displayname = [account displaynameForUUID:account.username safe:NO];
+ [self.tableView reloadData];
+ }
+ failure:^(OpenStackRequest *request) {
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ self.navigationItem.rightBarButtonItem.enabled = YES;
+ [self.tableView reloadData];
+ }];
} else {
- account.filesURL = [account.provider.authEndpointURL URLByAppendingPathComponent:account.username];
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ self.navigationItem.rightBarButtonItem.enabled = YES;
+ [self alert:@"Authentication Failure" message:@"Please check your Token and UUID."];
}
- [account persist];
- [[account.manager userCatalogForDisplaynames:nil
- UUIDs:[NSArray arrayWithObject:account.username]]
- success:^(OpenStackRequest *request) {
- [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
- self.displayname = [account displaynameForUUID:account.username safe:NO];
- }
- failure:^(OpenStackRequest *request) {
- [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
- }];
- } else {
+ }
+ failure:^(OpenStackRequest *request) {
[activityIndicatorView stopAnimatingAndRemoveFromSuperview];
self.navigationItem.rightBarButtonItem.enabled = YES;
- [self alert:@"Authentication Failure" message:@"Please check your UUID and Token."];
- }
- }
- failure:^(OpenStackRequest *request) {
- [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
- self.navigationItem.rightBarButtonItem.enabled = YES;
- if ([request responseStatusCode] == 401) {
- [self alert:@"Authentication Failure" message:@"Please check your UUID and Token."];
- } else {
- [self failOnBadConnection];
+ if ([request responseStatusCode] == 401) {
+ [self alert:@"Authentication Failure" message:@"Please check your Token and UUID."];
+ } else {
+ [self alert:nil request:request];
+ }
+ }];
+ } else {
+ [[temporaryAccount.manager serviceCatalog]
+ success:^(OpenStackRequest *request) {
+ if ([request isSuccess]) {
+ account.provider = request.account.provider;
+ account.authToken = request.account.authToken;
+ account.username = request.account.username;
+ account.ignoreSSLErrors = request.account.ignoreSSLErrors;
+ account.filesURL = [account.provider.authEndpointURL URLByAppendingPathComponent:account.username];
+ [account persist];
+ [[account.manager userCatalogForDisplaynames:nil UUIDs:[NSArray arrayWithObject:account.username]]
+ success:^(OpenStackRequest *request) {
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ self.navigationItem.rightBarButtonItem.enabled = YES;
+ self.username = account.username;
+ [self.tableView reloadData];
+ }
+ failure:^(OpenStackRequest *request) {
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ self.navigationItem.rightBarButtonItem.enabled = YES;
+ self.username = account.username;
+ [self.tableView reloadData];
+ }];
+ } else {
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ self.navigationItem.rightBarButtonItem.enabled = YES;
+ [self alert:@"Authentication Failure" message:@"Please check your Token."];
+ }
}
- }];
+ failure:^(OpenStackRequest *request) {
+ [activityIndicatorView stopAnimatingAndRemoveFromSuperview];
+ self.navigationItem.rightBarButtonItem.enabled = YES;
+ if (request.responseStatusCode == 404) {
+ self.providerPithosObjectStoreURLString = request.account.provider.pithosObjectStoreURL.description;
+ self.providerAstakosAccountURLString = request.account.provider.astakosAccountURL.description;
+ self.providerAstakosWebloginURLString = request.account.provider.astakosWebloginURL.description;
+ provider.manual = YES;
+ providerManualSwitch.on = YES;
+ [self.tableView reloadData];
+ [self alert:@"Authentication Failure" message:@"Please enter also your UUID."];
+ } else if ([request responseStatusCode] == 401) {
+ [self alert:@"Authentication Failure" message:@"Please check your Token."];
+ } else {
+ [self alert:nil request:request];
+ }
+ }];
+ }
}
}
NSString *title = @"Error";
if (request.responseStatusCode == 0) {
title = @"Connection Error";
- message = @"Please check your connection or API URL and try again.";
+ message = [NSString stringWithFormat:@"Please check your connection or API URL and try again. Error: %@", request.error];
}
self.logEntryModalViewController = [[[LogEntryModalViewController alloc] initWithNibName:@"LogEntryModalViewController" bundle:nil] autorelease];
cell.detailTextLabel.textAlignment = UITextAlignmentRight;
}
- if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
- cell.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.8];
- }
-
if (indexPath.section == kOverview) {
cell.accessoryType = UITableViewCellAccessoryNone;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[request addRequestHeader:@"Content-Type" value:@"application/json"];
request.timeOutSeconds = 60;
request.numberOfTimesToRetryOnTimeout = 5;
+ request.validatesSecureCertificate = !account.ignoreSSLErrors;
return request;
}
@implementation NSString (Conveniences)
- (BOOL)isURL {
-// return [self hasPrefix:@"http://"] || [self hasPrefix:@"https://"];
- return [[NSPredicate predicateWithFormat:@"SELF MATCHES %@",
- @"(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+"]
- evaluateWithObject:self];
+ return [self hasPrefix:@"http://"] || [self hasPrefix:@"https://"];
+// return [[NSPredicate predicateWithFormat:@"SELF MATCHES %@",
+// @"(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+"]
+// evaluateWithObject:self];
+// return [[NSPredicate predicateWithFormat:@"SELF MATCHES %@",
+// @"http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w-\\+ ./?%&=]*)?"]
+// evaluateWithObject:self];
}
- (NSString *)replace:(NSString *)s with:(NSString *)r {
@property (nonatomic, assign) BOOL shared;
@property (nonatomic, retain) NSString *sharingAccount;
@property (nonatomic, retain) NSMutableDictionary *userCatalog;
+@property (nonatomic, assign) BOOL ignoreSSLErrors;
+ (NSArray *)accounts;
+ (void)persist:(NSArray *)accountArray;
@synthesize uuid, provider, username, filesURL, manager,
bytesUsed, policyQuota, containers, hasBeenRefreshed, flaggedForDelete,
- shared, sharingAccount, userCatalog;
+ shared, sharingAccount, userCatalog, ignoreSSLErrors;
+ (void)initialize {
accounts = [[Archiver retrieve:@"accounts"] retain];
self.userCatalog = [NSMutableDictionary dictionary];
}
+ self.ignoreSSLErrors = [coder decodeBoolForKey:@"ignoreSSLErrors"];
+
manager = [[AccountManager alloc] init];
manager.account = self;
}
- (id)copyWithZone:(NSZone *)zone {
OpenStackAccount *copy = [[[self class] allocWithZone:zone] init];
- copy.uuid = self.uuid;
- copy.provider = self.provider;
- copy.username = self.username;
- copy.apiKey = self.apiKey;
- copy.authToken = self.authToken;
+ copy.uuid = [[self.uuid copy] autorelease];
+ copy.provider = [[self.provider copy] autorelease];
+ copy.username = [[self.username copy] autorelease];
+ copy.apiKey = [[self.apiKey copy] autorelease];
+ copy.authToken = [[self.authToken copy] autorelease];
- copy.filesURL = self.filesURL;
- copy.bytesUsed = self.bytesUsed;
- copy.policyQuota = self.policyQuota;
+ copy.filesURL = [[self.filesURL copy] autorelease];
+ copy.bytesUsed = [[self.bytesUsed copy] autorelease];
+ copy.policyQuota = [[self.policyQuota copy] autorelease];
copy.userCatalog = [[self.userCatalog copy] autorelease];
+ copy.ignoreSSLErrors = self.ignoreSSLErrors;
+
copy.manager = [[[AccountManager alloc] init] autorelease];
copy.manager.account = copy;
return copy;
// [coder encodeObject:containers forKey:@"containers"];
[coder encodeObject:userCatalog forKey:@"userCatalog"];
+
+ [coder encodeBool:ignoreSSLErrors forKey:@"ignoreSSLErrors"];
}
- (id)decode:(NSCoder *)coder key:(NSString *)key {
objectDownloadRequests = [[NSMutableDictionary alloc] init];
+ // Load and persist accounts once to allow any migration checks to take effect.
+ [OpenStackAccount persist:[OpenStackAccount accounts]];
+
[userDefaults synchronize];
}
if ([host hasPrefix:@"login"] && query) {
// user=
- NSString *authUser;
+ // optional
+ NSString *authUser = nil;
NSRange userRange = [query rangeOfString:@"user=" options:NSCaseInsensitiveSearch];
- if (userRange.length == 0)
- // XXX maybe show an error message?
- return NO;
- NSUInteger authUserStartLocation = userRange.location + userRange.length;
- NSRange userEndRange = [query rangeOfString:@"&" options:NSCaseInsensitiveSearch
- range:NSMakeRange(authUserStartLocation, [query length] - authUserStartLocation)];
- if (userEndRange.length) {
- authUser = [[query substringWithRange:NSMakeRange(authUserStartLocation, userEndRange.location - authUserStartLocation)]
- stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
- } else {
- authUser = [[query substringFromIndex:authUserStartLocation]
- stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+ if (userRange.length) {
+ NSUInteger authUserStartLocation = userRange.location + userRange.length;
+ NSRange userEndRange = [query rangeOfString:@"&" options:NSCaseInsensitiveSearch
+ range:NSMakeRange(authUserStartLocation, [query length] - authUserStartLocation)];
+ if (userEndRange.length) {
+ authUser = [[query substringWithRange:NSMakeRange(authUserStartLocation, userEndRange.location - authUserStartLocation)]
+ stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+ } else {
+ authUser = [[query substringFromIndex:authUserStartLocation]
+ stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+ }
}
// token=
- NSString *authToken;
+ // required
+ NSString *authToken = nil;
NSRange tokenRange = [query rangeOfString:@"token=" options:NSCaseInsensitiveSearch];
if (tokenRange.length == 0)
// XXX maybe show an error message?
if (vc) {
gotToken = YES;
if ([vc class] == [AccountDetailsViewController class]) {
- [((AccountDetailsViewController *)vc) setUsername:authUser andAuthToken:authToken];
+ ((AccountDetailsViewController *)vc).authToken = authToken;
+ ((AccountDetailsViewController *)vc).username = authUser;
[((AccountDetailsViewController *)vc).tableView reloadData];
} else if ([vc class] == [AccountSettingsViewController class]) {
- [((AccountSettingsViewController *)vc) setUsername:authUser andAuthToken:authToken];
+ ((AccountSettingsViewController *)vc).authToken = authToken;
+ ((AccountSettingsViewController *)vc).username = authUser;
[((AccountSettingsViewController *)vc).tableView reloadData];
}
}
@property (nonatomic, retain) APICallback *callback;
@property (nonatomic, retain) ErrorAlerter *errorAlerter;
++ (id)requestWithoutToken:(OpenStackAccount *)account method:(NSString *)method url:(NSURL *)url;
+ (id)request:(OpenStackAccount *)account method:(NSString *)method url:(NSURL *)url;
+ (id)filesRequest:(OpenStackAccount *)account method:(NSString *)method path:(NSString *)path;
++ (id)serviceCatalogRequest:(OpenStackAccount *)account;
+- (NSDictionary *)access;
+- (NSDictionary *)token;
+- (NSArray *)serviceCatalog;
+- (NSDictionary *)user;
+
+ (id)userCatalogRequest:(OpenStackAccount *)account displaynames:(NSArray *)displaynames UUIDs:(NSArray *)UUIDs;
- (NSDictionary *)catalogs;
- (NSDictionary *)displaynameCatalog;
#pragma mark - Constructors
#pragma mark Generic
-+ (id)request:(OpenStackAccount *)account method:(NSString *)method url:(NSURL *)url {
++ (id)requestWithoutToken:(OpenStackAccount *)account method:(NSString *)method url:(NSURL *)url {
OpenStackRequest *request = [[[self alloc] initWithURL:url] autorelease];
request.account = account;
request.requestMethod = method;
- [request addRequestHeader:@"X-Auth-Token" value:account.authToken];
[request addRequestHeader:@"Content-Type" value:@"application/json"];
request.timeOutSeconds = 60;
request.numberOfTimesToRetryOnTimeout = 5;
+ request.validatesSecureCertificate = !account.ignoreSSLErrors;
+ return request;
+}
+
++ (id)request:(OpenStackAccount *)account method:(NSString *)method url:(NSURL *)url {
+ OpenStackRequest *request = [self requestWithoutToken:account method:method url:url];
+ [request addRequestHeader:@"X-Auth-Token" value:account.authToken];
return request;
}
return [self request:account method:method url:url];
}
+#pragma mark Service Catalog
++ (id)serviceCatalogRequest:(OpenStackAccount *)account {
+ OpenStackRequest *request = [self requestWithoutToken:account method:@"POST" url:account.provider.tokensURL];
+ if (account.authToken.length)
+ [request appendPostData:[[NSString stringWithFormat:@"{\"auth\":{\"token\":{\"id\":\"%@\"}}}", account.authToken]
+ dataUsingEncoding:NSUTF8StringEncoding]];
+ return request;
+}
+
+- (NSDictionary *)access {
+ SBJSON *parser = [[[SBJSON alloc] init] autorelease];
+ NSDictionary *access = [[parser objectWithString:[self responseString]] objectForKey:@"access"];
+ return access;
+}
+
+- (NSDictionary *)token {
+ return [[self access] objectForKey:@"token"];
+}
+
+- (NSArray *)serviceCatalog {
+ return [[self access] objectForKey:@"serviceCatalog"];
+}
+
+- (NSArray *)user {
+ return [[self access] objectForKey:@"user"];
+}
+
#pragma mark User Catalog
+ (id)userCatalogRequest:(OpenStackAccount *)account displaynames:(NSArray *)displaynames UUIDs:(NSArray *)UUIDs {
OpenStackRequest *request = [self request:account method:@"POST" url:account.provider.userCatalogURL];
request.account = account;
request.requestMethod = @"GET";
[request addRequestHeader:@"X-Auth-User" value:account.username];
- [request addRequestHeader:@"X-Auth-Token" value:(account.authToken ? account.authToken : @"")];
+ [request addRequestHeader:@"X-Auth-Token" value:account.authToken];
request.timeOutSeconds = 60;
request.numberOfTimesToRetryOnTimeout = 5;
+ request.validatesSecureCertificate = !account.ignoreSSLErrors;
return request;
}
if (responseStatusCode == 503) {
NSNotification *notification = [NSNotification notificationWithName:@"serviceUnavailable" object:nil userInfo:nil];
[[NSNotificationCenter defaultCenter] postNotification:notification];
- } else if (responseStatusCode == 0) {
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- if (![defaults boolForKey:@"already_failed_on_connection"]) {
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Connection Error" message:@"Please check your connection or API URL and try again." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
- [alert show];
- [alert release];
- }
- [defaults setBool:YES forKey:@"already_failed_on_connection"];
- [defaults synchronize];
+ // This crashes the app, check if it can be removed completely.
+// } else if (responseStatusCode == 0) {
+// NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+// if (![defaults boolForKey:@"already_failed_on_connection"]) {
+// UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Connection Error" message:@"Please check your connection or API URL and try again." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
+// [alert show];
+// [alert release];
+// }
+// [defaults setBool:YES forKey:@"already_failed_on_connection"];
+// [defaults synchronize];
}
[super failWithError:theError];
// The OpenStack project is provided under the Apache 2.0 license.
//
-@interface Provider : NSObject <NSCoding> {
+@interface Provider : NSObject <NSCoding, NSCopying> {
NSString *name;
- NSURL *hostURL;
- NSString *version;
+ NSURL *authURL;
+ NSURL *pithosObjectStoreURL;
+ NSURL *astakosAccountURL;
+ NSURL *astakosWebloginURL;
+ BOOL manual;
}
+ (NSArray *)providers;
@property (nonatomic, retain) NSString *name;
-@property (nonatomic, retain) NSURL *hostURL;
-@property (nonatomic, retain) NSString *version;
+@property (nonatomic, retain) NSURL *authURL;
+@property (nonatomic, retain) NSURL *pithosObjectStoreURL;
+@property (nonatomic, retain) NSURL *astakosAccountURL;
+@property (nonatomic, retain) NSURL *astakosWebloginURL;
+@property (nonatomic) BOOL manual;
+@property (nonatomic, readonly) NSURL *tokensURL;
@property (nonatomic, readonly) NSURL *authEndpointURL;
@property (nonatomic, readonly) NSURL *loginURL;
@property (nonatomic, readonly) NSURL *userCatalogURL;
#import "Provider.h"
static NSArray *providers = nil;
+static NSString *defaultAuthURLString = @"https://accounts.okeanos.grnet.gr/astakos/identity/v2.0";
+static NSString *defaultManualURLString = @"https://pithos.okeanos.grnet.gr";
@implementation Provider
-@synthesize name, hostURL, version, authEndpointURL, loginURL, userCatalogURL, publicLinkURLPrefix;
+@synthesize name, authURL, pithosObjectStoreURL, astakosAccountURL, astakosWebloginURL, manual;
+@synthesize tokensURL, authEndpointURL, loginURL, userCatalogURL, publicLinkURLPrefix;
+ (NSArray *)providers {
if (providers == nil) {
Provider *provider = [[Provider alloc] init];
provider.name = @"okeanos";
- provider.hostURL = [NSURL URLWithString:@"https://pithos.okeanos.grnet.gr"];
- provider.version = @"v1";
+ provider.authURL = [NSURL URLWithString:defaultAuthURLString];
providers = [[NSArray alloc] initWithObjects:provider, nil];
[provider release];
}
#pragma mark - Serialization
+- (id)copyWithZone:(NSZone *)zone {
+ Provider *copy = [[[self class] allocWithZone:zone] init];
+ copy.name = self.name;
+ copy.authURL = self.authURL;
+ copy.pithosObjectStoreURL = self.pithosObjectStoreURL;
+ copy.astakosAccountURL = self.astakosAccountURL;
+ copy.astakosWebloginURL = self.astakosWebloginURL;
+ copy.manual = self.manual;
+ return copy;
+}
+
- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject:name forKey:@"name"];
- [coder encodeObject:hostURL forKey:@"hostURL"];
- [coder encodeObject:version forKey:@"version"];
+ [coder encodeObject:authURL forKey:@"authURL"];
+ [coder encodeObject:pithosObjectStoreURL forKey:@"pithosObjectStoreURL"];
+ [coder encodeObject:astakosAccountURL forKey:@"astakosAccountURL"];
+ [coder encodeObject:astakosWebloginURL forKey:@"astakosWebloginURL"];
+ [coder encodeBool:manual forKey:@"manual"];
+
}
- (id)initWithCoder:(NSCoder *)coder {
if ((self = [super init])) {
self.name = [coder decodeObjectForKey:@"name"];
- self.hostURL = [coder decodeObjectForKey:@"hostURL"];
- self.version = [coder decodeObjectForKey:@"version"];
+ self.authURL = [coder decodeObjectForKey:@"authURL"];
+ self.pithosObjectStoreURL = [coder decodeObjectForKey:@"pithosObjectStoreURL"];
+ self.astakosAccountURL = [coder decodeObjectForKey:@"astakosAccountURL"];
+ self.astakosWebloginURL = [coder decodeObjectForKey:@"astakosWebloginURL"];
+ self.manual = [coder decodeBoolForKey:@"manual"];
// Support for older versions.
- if (!hostURL) {
- NSURL *tmpURL = [coder decodeObjectForKey:@"authEndpointURL"];
- if (tmpURL) {
- self.hostURL = [tmpURL URLByDeletingLastPathComponent];
+ if (!authURL && !pithosObjectStoreURL && !astakosAccountURL && !astakosWebloginURL) {
+ NSURL *tmpURL = [coder decodeObjectForKey:@"hostURL"];
+ if (!tmpURL)
+ tmpURL = [[coder decodeObjectForKey:@"authEndpointURL"] URLByDeletingLastPathComponent];
+ if (!tmpURL)
+ tmpURL = [NSURL URLWithString:defaultManualURLString];
+ if ([[tmpURL URLByAppendingPathComponent:@""] isEqual:[[NSURL URLWithString:defaultManualURLString] URLByAppendingPathComponent:@""]] &&
+ [name isEqualToString:@"okeanos"]) {
+ self.authURL = [NSURL URLWithString:defaultAuthURLString];
+ self.manual = NO;
} else {
- self.hostURL = [NSURL URLWithString:@"https://pithos.okeanos.grnet.gr"];
+ self.pithosObjectStoreURL = [tmpURL URLByAppendingPathComponent:@"v1"];
+ self.astakosAccountURL = [[tmpURL copy] autorelease];
+ self.astakosWebloginURL = [[tmpURL copy] autorelease];
+ self.manual = YES;
}
}
- if (!version) {
- self.version = @"v1";
- }
}
return self;
}
- (void)dealloc {
[name release];
- [hostURL release];
- [version release];
+ [authURL release];
+ [pithosObjectStoreURL release];
+ [astakosAccountURL release];
+ [astakosWebloginURL release];
[super dealloc];
}
#pragma mark - Properties
+- (NSURL *)tokensURL {
+ return [authURL URLByAppendingPathComponent:@"tokens"];
+}
+
- (NSURL *)authEndpointURL {
- return [hostURL URLByAppendingPathComponent:version];
+ return pithosObjectStoreURL;
}
- (NSURL *)loginURL {
- return [hostURL URLByAppendingPathComponent:@"login"];
+ return [astakosWebloginURL URLByAppendingPathComponent:@"login"];
}
- (NSURL *)userCatalogURL {
- return [hostURL URLByAppendingPathComponent:@"user_catalogs"];
+ return [astakosAccountURL URLByAppendingPathComponent:@"user_catalogs"];
}
- (NSURL *)publicLinkURLPrefix {
- return hostURL;
+ return pithosObjectStoreURL;
}
@end
} else {
Provider *provider = [[Provider providers] objectAtIndex:indexPath.row];
cell.textLabel.text = provider.name;
- cell.detailTextLabel.text = [provider.authEndpointURL absoluteString];
+ cell.detailTextLabel.text = [provider.authURL absoluteString];
cell.imageView.image = [UIImage imageNamed:@"pithos-solo-smallest.png"];
}
return cell;
@synthesize textField, modalPresentationStyle, fixedTextLabel;
-- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
- self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
- if (self) {
- [self initializeSubviews:style withFixedTextLabel:nil];
- }
- return self;
-}
-
- (id)initCellWithFixedLabel:(NSString *)fixedLabelText withStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
- self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
- if (self) {
+ if ((self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) {
[self initializeSubviews:style withFixedTextLabel:fixedLabelText];
}
return self;
}
+
+- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
+ return [self initCellWithFixedLabel:nil withStyle:style reuseIdentifier:reuseIdentifier];
+}
- (void)initializeSubviews:(UITableViewCellStyle)style withFixedTextLabel:(NSString *)fixedLabelText {
self.selectionStyle = UITableViewCellSelectionStyleNone;
}
cell.textLabel.textColor = [UIColor blackColor];
cell.detailTextLabel.numberOfLines = 0;
- if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
- cell.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.8];
- }
cell.userInteractionEnabled = YES;
cell.detailTextLabel.textAlignment = UITextAlignmentRight;
cell.accessoryView = nil;
}
- (void)alert:(NSString *)message request:(OpenStackRequest *)request addAccountSettingsButton:(BOOL)addAccountSettingsButton {
- request.errorAlerter = [[[ErrorAlerter alloc] init] autorelease];
- if ((request.responseStatusCode == 401) || request.responseStatusCode == 403) {
- message = [message stringByAppendingString:@" Authorization failed. Please check your Username and Token."];
+ request.errorAlerter = [[[ErrorAlerter alloc] init] autorelease];
+ if ((request.responseStatusCode == 401) || request.responseStatusCode == 403) {
+ message = [message stringByAppendingString:@" Authorization failed. Please check your Token."];
} else if (request.responseStatusCode == 503) {
message = [message stringByAppendingString:@" Service is currently unavailable. Please try again later."];
}
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
- <string>1.6.4</string>
+ <string>1.7.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
</dict>
</array>
<key>CFBundleVersion</key>
- <string>20130502.0</string>
+ <string>20130625.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSMainNibFile</key>