Commit a0f03265 authored by Luci Stanescu's avatar Luci Stanescu

Improved the handling of duplicate SIP addresses in Add Account dialog

parent 2571a750
...@@ -22,7 +22,7 @@ from application.python.util import Null ...@@ -22,7 +22,7 @@ from application.python.util import Null
from gnutls.errors import GNUTLSError from gnutls.errors import GNUTLSError
from zope.interface import implements from zope.interface import implements
from sipsimple.account import Account, AccountManager, BonjourAccount from sipsimple.account import Account, AccountExists, AccountManager, BonjourAccount
from sipsimple.configuration.settings import SIPSimpleSettings from sipsimple.configuration.settings import SIPSimpleSettings
from sipsimple.util import user_info from sipsimple.util import user_info
...@@ -232,6 +232,8 @@ ui_class, base_class = uic.loadUiType(Resources.get('add_account.ui')) ...@@ -232,6 +232,8 @@ ui_class, base_class = uic.loadUiType(Resources.get('add_account.ui'))
class AddAccountDialog(base_class, ui_class): class AddAccountDialog(base_class, ui_class):
__metaclass__ = QSingleton __metaclass__ = QSingleton
implements(IObserver)
def __init__(self, parent=None): def __init__(self, parent=None):
super(AddAccountDialog, self).__init__(parent) super(AddAccountDialog, self).__init__(parent)
with Resources.directory: with Resources.directory:
...@@ -271,6 +273,10 @@ class AddAccountDialog(base_class, ui_class): ...@@ -271,6 +273,10 @@ class AddAccountDialog(base_class, ui_class):
self.verify_password_editor.regexp = re.compile('^$') self.verify_password_editor.regexp = re.compile('^$')
self.email_address_editor.regexp = re.compile('^[^@\s]+@[^@\s]+$') self.email_address_editor.regexp = re.compile('^[^@\s]+@[^@\s]+$')
account_manager = AccountManager()
notification_center = NotificationCenter()
notification_center.add_observer(self, sender=account_manager)
def _get_display_name(self): def _get_display_name(self):
if self.panel_view.currentWidget() is self.add_account_panel: if self.panel_view.currentWidget() is self.add_account_panel:
return unicode(self.display_name_editor.text()) return unicode(self.display_name_editor.text())
...@@ -347,7 +353,7 @@ class AddAccountDialog(base_class, ui_class): ...@@ -347,7 +353,7 @@ class AddAccountDialog(base_class, ui_class):
inputs = [self.display_name_editor, self.sip_address_editor, self.password_editor] inputs = [self.display_name_editor, self.sip_address_editor, self.password_editor]
else: else:
inputs = [self.name_editor, self.username_editor, self.new_password_editor, self.verify_password_editor, self.email_address_editor] inputs = [self.name_editor, self.username_editor, self.new_password_editor, self.verify_password_editor, self.email_address_editor]
self.accept_button.setEnabled(all(input.valid for input in inputs)) self.accept_button.setEnabled(all(input.text_valid for input in inputs))
def _SH_PasswordTextChanged(self, text): def _SH_PasswordTextChanged(self, text):
self.verify_password_editor.regexp = re.compile(u'^%s$' % re.escape(unicode(text))) self.verify_password_editor.regexp = re.compile(u'^%s$' % re.escape(unicode(text)))
...@@ -355,24 +361,28 @@ class AddAccountDialog(base_class, ui_class): ...@@ -355,24 +361,28 @@ class AddAccountDialog(base_class, ui_class):
def _SH_ValidityStatusChanged(self): def _SH_ValidityStatusChanged(self):
red = '#cc0000' red = '#cc0000'
# validate the add panel # validate the add panel
if not self.display_name_editor.valid: if not self.display_name_editor.text_valid:
self.add_status_label.value = Status("Display name cannot be empty", color=red) self.add_status_label.value = Status("Display name cannot be empty", color=red)
elif not self.sip_address_editor.valid: elif not self.sip_address_editor.text_correct:
self.add_status_label.value = Status("SIP address should be specified as user@domain", color=red) self.add_status_label.value = Status("SIP address should be specified as user@domain", color=red)
elif not self.password_editor.valid: elif not self.sip_address_editor.text_allowed:
self.add_status_label.value = Status("SIP address in use by another account", color=red)
elif not self.password_editor.text_valid:
self.add_status_label.value = Status("Password cannot be empty", color=red) self.add_status_label.value = Status("Password cannot be empty", color=red)
else: else:
self.add_status_label.value = None self.add_status_label.value = None
# validate the create panel # validate the create panel
if not self.name_editor.valid: if not self.name_editor.text_valid:
self.create_status_label.value = Status("Name cannot be empty", color=red) self.create_status_label.value = Status("Name cannot be empty", color=red)
elif not self.username_editor.valid: elif not self.username_editor.text_correct:
self.create_status_label.value = Status("Username should have 5 to 32 characters, start with a letter or non-zero digit, contain only letters, digits or .-_ and end with a letter or digit", color=red) self.create_status_label.value = Status("Username should have 5 to 32 characters, start with a letter or non-zero digit, contain only letters, digits or .-_ and end with a letter or digit", color=red)
elif not self.new_password_editor.valid: elif not self.username_editor.text_allowed:
self.create_status_label.value = Status("The username you requested is already taken. Please choose another one and try again.", color=red)
elif not self.new_password_editor.text_valid:
self.create_status_label.value = Status("Password should contain at least 8 characters", color=red) self.create_status_label.value = Status("Password should contain at least 8 characters", color=red)
elif not self.verify_password_editor.valid: elif not self.verify_password_editor.text_valid:
self.create_status_label.value = Status("Passwords do not match", color=red) self.create_status_label.value = Status("Passwords do not match", color=red)
elif not self.email_address_editor.valid: elif not self.email_address_editor.text_valid:
self.create_status_label.value = Status("E-mail address should be specified as user@domain", color=red) self.create_status_label.value = Status("E-mail address should be specified as user@domain", color=red)
else: else:
self.create_status_label.value = None self.create_status_label.value = None
...@@ -381,7 +391,7 @@ class AddAccountDialog(base_class, ui_class): ...@@ -381,7 +391,7 @@ class AddAccountDialog(base_class, ui_class):
inputs = [self.display_name_editor, self.sip_address_editor, self.password_editor] inputs = [self.display_name_editor, self.sip_address_editor, self.password_editor]
else: else:
inputs = [self.name_editor, self.username_editor, self.new_password_editor, self.verify_password_editor, self.email_address_editor] inputs = [self.name_editor, self.username_editor, self.new_password_editor, self.verify_password_editor, self.email_address_editor]
self.accept_button.setEnabled(all(input.valid for input in inputs)) self.accept_button.setEnabled(all(input.text_valid for input in inputs))
def _initialize(self): def _initialize(self):
self.display_name = user_info.fullname self.display_name = user_info.fullname
...@@ -421,7 +431,11 @@ class AddAccountDialog(base_class, ui_class): ...@@ -421,7 +431,11 @@ class AddAccountDialog(base_class, ui_class):
certificate_path = Blink().save_certificates(response_data['sip_address'], passport['crt'], passport['key'], passport['ca']) certificate_path = Blink().save_certificates(response_data['sip_address'], passport['crt'], passport['key'], passport['ca'])
except (GNUTLSError, IOError, OSError): except (GNUTLSError, IOError, OSError):
pass pass
account = Account(response_data['sip_address']) account_manager = AccountManager()
try:
account = Account(response_data['sip_address'])
except AccountExists:
account = account_manager.get_account(response_data['sip_address'])
account.enabled = True account.enabled = True
account.display_name = display_name account.display_name = display_name
account.auth.password = password account.auth.password = password
...@@ -431,11 +445,10 @@ class AddAccountDialog(base_class, ui_class): ...@@ -431,11 +445,10 @@ class AddAccountDialog(base_class, ui_class):
account.tls.certificate = certificate_path account.tls.certificate = certificate_path
account.server.settings_url = response_data['settings_url'] account.server.settings_url = response_data['settings_url']
account.save() account.save()
account_manager = AccountManager()
account_manager.default_account = account account_manager.default_account = account
call_in_gui_thread(self.accept) call_in_gui_thread(self.accept)
elif response_data['error'] == 'user_exists': elif response_data['error'] == 'user_exists':
call_in_gui_thread(setattr, self.create_status_label, 'value', Status('The username you requested is already taken. Please choose another one and try again.', color=red)) call_in_gui_thread(self.username_editor.addException, username)
else: else:
call_in_gui_thread(setattr, self.create_status_label, 'value', Status(response_data['error_message'], color=red)) call_in_gui_thread(setattr, self.create_status_label, 'value', Status(response_data['error_message'], color=red))
except (cjson.DecodeError, KeyError): except (cjson.DecodeError, KeyError):
...@@ -445,6 +458,18 @@ class AddAccountDialog(base_class, ui_class): ...@@ -445,6 +458,18 @@ class AddAccountDialog(base_class, ui_class):
finally: finally:
call_in_gui_thread(self.setEnabled, True) call_in_gui_thread(self.setEnabled, True)
@run_in_gui_thread
def handle_notification(self, notification):
handler = getattr(self, '_NH_%s' % notification.name, Null)
handler(notification)
def _NH_SIPAccountManagerDidAddAccount(self, notification):
account = notification.data.account
self.sip_address_editor.addException(notification.data.account.id)
def _NH_SIPAccountManagerDidRemoveAccount(self, notification):
self.sip_address_editor.removeException(notification.data.account.id)
def open_for_add(self): def open_for_add(self):
self.add_account_button.click() self.add_account_button.click()
self.add_account_button.setFocus() self.add_account_button.setFocus()
......
...@@ -140,7 +140,9 @@ class ValidatingLineEdit(LineEdit): ...@@ -140,7 +140,9 @@ class ValidatingLineEdit(LineEdit):
frame_width = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth, option, self) frame_width = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth, option, self)
self.setMinimumHeight(self.invalid_entry_label.minimumHeight() + 2 + 2*frame_width) self.setMinimumHeight(self.invalid_entry_label.minimumHeight() + 2 + 2*frame_width)
self.textChanged.connect(self.text_changed) self.textChanged.connect(self.text_changed)
self.valid = True self.text_correct = True
self.text_allowed = True
self.exceptions = set()
self.regexp = re.compile(r'.*') self.regexp = re.compile(r'.*')
def _get_regexp(self): def _get_regexp(self):
...@@ -148,22 +150,36 @@ class ValidatingLineEdit(LineEdit): ...@@ -148,22 +150,36 @@ class ValidatingLineEdit(LineEdit):
def _set_regexp(self, regexp): def _set_regexp(self, regexp):
self.__dict__['regexp'] = regexp self.__dict__['regexp'] = regexp
valid = regexp.search(unicode(self.text())) is not None self.validate()
if self.valid != valid:
self.invalid_entry_label.setVisible(not valid)
self.valid = valid
self.statusChanged.emit()
regexp = property(_get_regexp, _set_regexp) regexp = property(_get_regexp, _set_regexp)
del _get_regexp, _set_regexp del _get_regexp, _set_regexp
@property
def text_valid(self):
return self.text_correct and self.text_allowed
def text_changed(self, text): def text_changed(self, text):
valid = self.regexp.search(unicode(text)) is not None self.validate()
if self.valid != valid:
self.invalid_entry_label.setVisible(not valid) def validate(self):
self.valid = valid text = unicode(self.text())
text_correct = self.regexp.search(text) is not None
text_allowed = text not in self.exceptions
if self.text_correct != text_correct or self.text_allowed != text_allowed:
self.text_correct = text_correct
self.text_allowed = text_allowed
self.invalid_entry_label.setVisible(not self.text_valid)
self.statusChanged.emit() self.statusChanged.emit()
def addException(self, exception):
self.exceptions.add(exception)
self.validate()
def removeException(self, exception):
self.exceptions.remove(exception)
self.validate()
class SearchIcon(QWidget): class SearchIcon(QWidget):
def __init__(self, parent=None, size=16): def __init__(self, parent=None, size=16):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment