//
// LoginPanelController.m
// Perforce
//
// Created by Adam Czubernat on 13.05.2013.
// Copyright (c) 2013 Perforce Software, Inc. All rights reserved.
//
#import "LoginPanelController.h"
#import "P4Workspace.h"
@interface LoginPanelController () {
NSString *host;
NSString *username;
NSString *workspace;
NSArray *servers;
enum {
panelTypeLogin,
panelTypeConnection,
panelTypeRelogin,
} panelType;
// Login
__weak IBOutlet NSView *loginView;
__weak IBOutlet NSTextField *usernameTextField;
__weak IBOutlet NSTextField *passwordTextField;
// Connection
__weak IBOutlet NSView *connectionView;
__weak IBOutlet NSComboBox *connectionComboBox;
__weak IBOutlet NSTextField *connectionAddressField;
__weak IBOutlet NSTextField *connectionUsernameField;
__weak IBOutlet NSTextField *connectionPasswordField;
__weak IBOutlet NSButton *connectionCancelButton;
// Relogin
__weak IBOutlet NSView *reloginView;
__weak IBOutlet NSTextField *reloginPasswordField;
// Loading
__weak IBOutlet NSView *loadingView;
__weak IBOutlet NSProgressIndicator *loadingIndicator;
__weak IBOutlet NSTextField *loadingLabel;
// SSO
__weak IBOutlet NSButton *ssoCheckbox;
}
- (void)automaticLogin;
- (void)loadWorkspace;
- (void)failWithError:(NSError *)error;
- (void)loginWithCredentials:(P4Credentials *)credentials;
- (void)showLoginView;
- (void)showConnectionView;
- (void)showReloginView;
- (IBAction)cancelPressed:(id)sender;
- (IBAction)loginPressed:(id)sender;
- (IBAction)connectionDetailsPressed:(id)sender;
- (IBAction)comboBoxSelected:(id)sender;
- (IBAction)connectPressed:(id)sender;
- (IBAction)reloginPressed:(id)sender;
- (IBAction)disconnectPressed:(id)sender;
- (IBAction)ssoCheckboxPressed:(id)sender;
@end
@implementation LoginPanelController
@synthesize delegate, allowsAutomaticLogin, allowsSSOLogin;
- (void)windowDidLoad {
[super windowDidLoad];
host = [NSUserDefaults stringForKey:kDefaultHost];
username = [NSUserDefaults stringForKey:kDefaultUsername];
workspace = [NSUserDefaults stringForKey:kDefaultWorkspace];
#ifdef DEBUG
// [addressTextField setStringValue:@"test-server.homelinux.org:16660"];
// [addressTextField setStringValue:@"ec2-50-16-43-78.compute-1.amazonaws.com:1666"];
// [usernameTextField setStringValue:@"a.czubernat"];
// [passwordTextField setStringValue:@"p@ssw0rd"];
[passwordTextField setStringValue:@"adam23"];
#endif
if (panelType == panelTypeLogin) {
if (allowsAutomaticLogin && workspace.length)
[self automaticLogin];
else if (host.length)
[self showLoginView];
else
[self showConnectionView];
} else if (panelType == panelTypeConnection) {
[self showConnectionView];
} else if (panelType == panelTypeRelogin) {
[self showReloginView];
}
}
#pragma mark - Public
+ (LoginPanelController *)connectionPanel {
LoginPanelController *panel = [[LoginPanelController alloc] init];
panel->panelType = panelTypeConnection;
return panel;
}
+ (LoginPanelController *)loginPanel {
LoginPanelController *panel = [[LoginPanelController alloc] init];
panel->panelType = panelTypeLogin;
return panel;
}
+ (LoginPanelController *)reloginPanel {
LoginPanelController *panel = [[LoginPanelController alloc] init];
panel->panelType = panelTypeRelogin;
return panel;
}
#pragma mark - Private
- (void)automaticLogin {
P4Credentials *credentials = [[P4Credentials alloc] init];
credentials.username = username;
credentials.address = host;
[self setPresentedView:loadingView animated:YES];
[loadingIndicator startAnimation:nil];
[loadingLabel setStringValue:@"Connecting..."];
PSLog(@"Automatic login...");
// Connect to host
[[P4Workspace sharedInstance]
connectWithCredentials:credentials
response:^(P4Operation *operation, NSArray *response) {
if (operation.errors) {
PSLog(@"Failed to connect");
[self showLoginView];
return;
}
// Try last session
credentials.resumeSession = YES;
[[P4Workspace sharedInstance]
loginWithCredentials:credentials
response:^(P4Operation *operation, NSArray *response) {
if (operation.errors) {
PSLog(@"Failed logging-in using last session");
PSLog(@"Automatic login using SSO...");
// Try SSO login
[[P4Workspace sharedInstance]
loginWithSSO:credentials
response:^(P4Operation *operation, NSArray *response) {
if (operation.errors) {
PSLog(@"Failed to login using SSO");
[self showLoginView];
return;
}
PSLog(@"Logged-in using SSO");
[self loadWorkspace];
}];
return;
}
PSLog(@"Logged-in using last session");
[self loadWorkspace];
}];
}];
}
- (void)loadWorkspace {
[[P4Workspace sharedInstance]
setWorkspace:workspace
response:^(P4Operation *operation, NSArray *response) {
[loadingIndicator stopAnimation:nil];
if (operation.errors) {
PSLog(@"Couldn't use last workspace %@", workspace);
[self showLoginView];
if ([delegate respondsToSelector:@selector(loginPanelDidLogin)])
[delegate loginPanelDidLogin];
} else {
PSLog(@"Connected to last workspace: %@", workspace);
PSLogStore(@"Workspace info", @"%@", response);
if ([delegate respondsToSelector:@selector(loginPanelDidLoginWithWorkspace:)])
[delegate loginPanelDidLoginWithWorkspace:workspace];
}
}];
}
- (void)failWithError:(NSError *)error {
[loadingIndicator stopAnimation:nil];
[self showLoginView];
[[NSAlert alertWithError:error]
beginSheetModalForWindow:self.window
modalDelegate:nil
didEndSelector:nil
contextInfo:NULL];
}
- (void)loginWithCredentials:(P4Credentials *)credentials {
[self setPresentedView:loadingView animated:YES];
[loadingIndicator startAnimation:nil];
[loadingLabel setStringValue:@"Logging in..."];
// Logout if logged in
if ([[P4Workspace sharedInstance] isLoggedIn]) {
[[P4Workspace sharedInstance] logout:^(P4Operation *operation, NSArray *response) {
[self loginWithCredentials:credentials];
}];
return;
}
PSLog(@"Logging in...");
// Response block
P4ResponseBlock_t loginResponseBlock = ^(P4Operation *operation, NSArray *response) {
if (operation.errors) {
[self failWithError:operation.error];
return;
}
// Connected
PSLog(@"Connected");
[loadingIndicator stopAnimation:nil];
[self showLoginView];
// Save last login details
[NSUserDefaults setString:credentials.address forKey:kDefaultHost];
[NSUserDefaults setString:credentials.username forKey:kDefaultUsername];
if ([delegate respondsToSelector:@selector(loginPanelDidLogin)])
[delegate loginPanelDidLogin];
};
// Connect with specified host
[[P4Workspace sharedInstance]
connectWithCredentials:credentials
response:^(P4Operation *operation, NSArray *response) {
if (operation.errors) {
[self failWithError:operation.error];
return;
}
if (allowsSSOLogin) {
[[P4Workspace sharedInstance]
loginWithSSO:credentials
response:loginResponseBlock];
} else {
[[P4Workspace sharedInstance]
loginWithCredentials:credentials
response:loginResponseBlock];
}
}];
}
- (void)showLoginView {
[loadingIndicator stopAnimation:nil];
usernameTextField.stringValue = username ?: @"";
[self setPresentedView:loginView animated:YES];
}
- (void)showConnectionView {
connectionAddressField.stringValue = host ?: @"";
connectionUsernameField.stringValue = username ?: @"";
[connectionCancelButton setEnabled:
[[P4Workspace sharedInstance] isLoggedIn] &&
[[P4Workspace sharedInstance] workspace]];
// Load servers list
NSString *plist = [[NSBundle mainBundle] pathForResource:@"Servers" ofType:@"plist"];
servers = [NSArray arrayWithContentsOfFile:plist];
NSArray *names = [servers valueForKeyPath:@"name"];
NSArray *addresses = [servers valueForKeyPath:@"address"];
[connectionComboBox removeAllItems];
[connectionComboBox addItemsWithObjectValues:names];
// Select server if last address matches one in the list
NSInteger idx = [addresses indexOfObject:host];
if (idx != NSNotFound)
[connectionComboBox selectItemAtIndex:idx];
[ssoCheckbox setState:allowsSSOLogin];
[self setPresentedView:connectionView animated:YES];
[self.window makeFirstResponder:connectionPasswordField];
}
- (void)showReloginView {
[self setPresentedView:reloginView animated:YES];
}
#pragma mark - Actions
- (IBAction)cancelPressed:(id)sender {
if ([delegate respondsToSelector:@selector(loginPanelDidCancel)])
[delegate loginPanelDidCancel];
}
- (IBAction)loginPressed:(NSButton *)sender {
P4Credentials *credentials = [[P4Credentials alloc] init];
credentials.address = host;
credentials.username = username = usernameTextField.stringValue;
credentials.password = passwordTextField.stringValue;
connectionPasswordField.stringValue = passwordTextField.stringValue;
[self loginWithCredentials:credentials];
}
- (IBAction)connectionDetailsPressed:(id)sender {
username = usernameTextField.stringValue;
connectionPasswordField.stringValue = passwordTextField.stringValue;
[self showConnectionView];
}
- (IBAction)comboBoxSelected:(id)sender {
NSInteger idx = [connectionComboBox indexOfSelectedItem];
NSString *address = [[servers objectAtIndex:idx] objectForKey:@"address"];
connectionAddressField.stringValue = address ?: @"";
}
- (IBAction)connectPressed:(id)sender {
P4Credentials *credentials = [[P4Credentials alloc] init];
credentials.address = host = connectionAddressField.stringValue;
credentials.username = username = connectionUsernameField.stringValue;
credentials.password = connectionPasswordField.stringValue;
passwordTextField.stringValue = connectionPasswordField.stringValue;
[self loginWithCredentials:credentials];
}
- (IBAction)reloginPressed:(NSButton *)sender {
P4Credentials *credentials = [[P4Credentials alloc] init];
credentials.password = reloginPasswordField.stringValue;
sender.enabled = NO;
[self setPresentedView:loadingView animated:YES];
[loadingIndicator startAnimation:nil];
[loadingLabel setStringValue:@"Reconnecting..."];
[[P4Workspace sharedInstance]
reloginWithCredentials:credentials
response:^(P4Operation *operation, NSArray *response) {
sender.enabled = YES;
[loadingIndicator stopAnimation:nil];
if (operation.errors) {
[self setPresentedView:reloginView animated:YES];
PSLog(@"Failed to reconnect");
NSError *error = operation.error;
[[NSAlert alertWithError:error]
beginSheetModalForWindow:self.window
modalDelegate:nil
didEndSelector:nil
contextInfo:NULL];
} else {
if ([delegate respondsToSelector:@selector(loginPanelDidRelogin)])
[delegate loginPanelDidRelogin];
}
}];
}
- (IBAction)disconnectPressed:(id)sender {
[self setPresentedView:loadingView animated:YES];
[loadingIndicator startAnimation:nil];
[loadingLabel setStringValue:@"Logging out..."];
[[P4Workspace sharedInstance] logout:^(P4Operation *operation, NSArray *response) {
[loadingIndicator stopAnimation:nil];
[self setPresentedView:loginView animated:YES];
}];
}
- (IBAction)ssoCheckboxPressed:(id)sender {
allowsSSOLogin = ssoCheckbox.state;
}
@end