1
# -*- coding: utf-8 -*-
2
# Author: Manuel de la Pena <manuel@canonical.com>
4
# Copyright 2011 Canonical Ltd.
6
# This program is free software: you can redistribute it and/or modify it
7
# under the terms of the GNU General Public License version 3, as published
8
# by the Free Software Foundation.
10
# This program is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranties of
12
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13
# PURPOSE. See the GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License along
16
# with this program. If not, see <http://www.gnu.org/licenses/>.
17
"""Controllers with the logic of the UI."""
28
from PyQt4.QtGui import QMessageBox, QWizard, QPixmap
29
from PyQt4.QtCore import QUrl
30
from twisted.internet.defer import inlineCallbacks, returnValue
32
from ubuntu_sso import NO_OP
33
from ubuntu_sso.logger import setup_logging
34
from ubuntu_sso.utils.ui import (
36
CAPTCHA_SOLUTION_ENTRY,
43
EXISTING_ACCOUNT_CHOICE_BUTTON,
44
FORGOTTEN_PASSWORD_BUTTON,
53
REQUEST_PASSWORD_TOKEN_LABEL,
56
REQUEST_PASSWORD_TOKEN_WRONG_EMAIL,
57
REQUEST_PASSWORD_TOKEN_TECH_ERROR,
58
SET_UP_ACCOUNT_CHOICE_BUTTON,
59
SET_UP_ACCOUNT_BUTTON,
68
is_min_required_password,
72
logger = setup_logging('ubuntu_sso.controllers')
73
FAKE_URL = '<a href="http://one.ubuntu.com">%s</a>'
75
# pylint: disable=W0511
76
# disabled warnings about TODO comments
79
class BackendController(object):
80
"""Represent a controller that talks with the sso self.backend."""
83
"""Create a new instance."""
89
"""Clean the resources."""
90
logger.info('Unregistering %s backend', self.backend)
91
self.backend.unregister_to_signals()
92
if self.root is not None:
93
logger.info('Disconnecting from root.')
94
self.root.disconnect()
97
def get_backend(self):
98
"""Return the backend used by the controller."""
99
# get the back end from the root
100
if self.root is None:
101
from ubuntu_sso.main.windows import UbuntuSSOClient
102
self.root = UbuntuSSOClient()
103
self.root = yield self.root.connect()
104
self.backend = self.root.sso_login
105
yield self.backend.register_to_signals()
106
returnValue(self.backend)
109
class ChooseSignInController(object):
110
"""Controlled to the ChooseSignIn view/widget."""
112
def __init__(self, title=''):
113
"""Create a new instance to manage the view."""
117
# use an ugly name just so have a simlar api as found in PyQt
118
#pylint: disable=C0103
119
def setupUi(self, view):
120
"""Perform the required actions to set up the ui."""
122
self.view.setTitle(self._title)
123
self._set_up_translated_strings()
124
self._connect_buttons()
125
#pylint: enable=C0103
127
def _set_up_translated_strings(self):
128
"""Set the correct strings for the UI."""
129
logger.debug('ChooseSignInController._set_up_translated_strings')
130
self.view.ui.existing_account_button.setText(
131
EXISTING_ACCOUNT_CHOICE_BUTTON)
132
self.view.ui.setup_account_button.setText(
133
SET_UP_ACCOUNT_CHOICE_BUTTON)
135
def _connect_buttons(self):
136
"""Connect the buttons to the actions to perform."""
137
logger.debug('ChooseSignInController._connect_buttons')
138
self.view.ui.existing_account_button.clicked.connect(
139
self._set_next_existing)
140
self.view.ui.setup_account_button.clicked.connect(self._set_next_new)
142
def _set_next_existing(self):
143
"""Set the next id and fire signal."""
144
logger.debug('ChooseSignInController._set_next_existing')
145
self.view.next = self.view.wizard().current_user_page_id
146
self.view.wizard().next()
148
def _set_next_new(self):
149
"""Set the next id and fire signal."""
150
logger.debug('ChooseSignInController._set_next_new')
151
self.view.next = self.view.wizard().setup_account_page_id
152
self.view.wizard().next()
155
class CurrentUserController(BackendController):
156
"""Controller used in the view that is used to allow the signin."""
158
def __init__(self, backend=None, title='', subtitle='', message_box=None):
159
"""Create a new instance."""
160
super(CurrentUserController, self).__init__()
161
if message_box is None:
162
message_box = QMessageBox
163
self.message_box = message_box
165
self._subtitle = subtitle
167
def _set_translated_strings(self):
168
"""Set the translated strings."""
169
logger.debug('CurrentUserController._set_translated_strings')
170
self.view.ui.email_label.setText(EMAIL_LABEL)
171
self.view.ui.email_edit.setPlaceholderText(EMAIL1_ENTRY)
172
self.view.ui.password_label.setText(LOGIN_PASSWORD_LABEL)
173
self.view.ui.password_edit.setPlaceholderText(PASSWORD1_ENTRY)
174
self.view.ui.forgot_password_label.setText(
175
FAKE_URL % FORGOTTEN_PASSWORD_BUTTON)
176
self.view.ui.sign_in_button.setText(SIGN_IN_BUTTON)
178
def _connect_ui(self):
179
"""Connect the buttons to perform actions."""
180
logger.debug('CurrentUserController._connect_buttons')
181
self.view.ui.sign_in_button.clicked.connect(self.login)
182
# lets add call backs to be execute for the calls we are interested
183
self.backend.on_login_error_cb = lambda app, error:\
184
self.on_login_error(error)
185
self.backend.on_logged_in_cb = self.on_logged_in
186
self.view.ui.forgot_password_label.linkActivated.connect(
187
self.on_forgotten_password)
190
"""Perform the login using the self.backend."""
191
logger.debug('CurrentUserController.login')
192
# grab the data from the view and call the backend
193
email = str(self.view.ui.email_edit.text())
194
password = str(self.view.ui.password_edit.text())
195
d = self.backend.login(self.view.wizard().app_name, email, password)
196
d.addErrback(self.on_login_error)
198
def on_login_error(self, error):
199
"""There was an error when login in."""
201
logger.error('Got error when login %s, error: %s',
202
self.view.wizard().app_name, error)
203
self.message_box.critical(self.view, self.view.wizard().app_name,
206
def on_logged_in(self, app_name, result):
207
"""We managed to log in."""
208
logger.info('Logged in for %s', app_name)
209
email = str(self.view.ui.email_edit.text())
210
self.view.wizard().loginSuccess.emit(app_name, email)
211
logger.debug('Wizard.loginSuccess emitted.')
213
def on_forgotten_password(self):
214
"""Show the user the forgotten password page."""
215
logger.info('Forgotten password')
216
self.view.next = self.view.wizard().forgotten_password_page_id
217
self.view.wizard().next()
219
# use an ugly name just so have a simlar api as found in PyQt
220
#pylint: disable=C0103
222
def setupUi(self, view):
223
"""Setup the view."""
225
self.backend = yield self.get_backend()
226
self.view.setTitle(self._title)
228
self.view.setSubTitle(self._subtitle)
229
self._set_translated_strings()
231
#pylint: enable=C0103
234
class SetUpAccountController(BackendController):
235
"""Conroller for the setup account view."""
237
def __init__(self, message_box=None):
238
"""Create a new instance."""
239
super(SetUpAccountController, self).__init__()
240
if message_box is None:
241
message_box = QMessageBox
242
self.message_box = message_box
244
def _set_translated_strings(self):
245
"""Set the different gettext translated strings."""
246
logger.debug('SetUpAccountController._set_translated_strings')
247
# set the translated string
248
self.view.ui.name_label.setText(NAME_ENTRY)
249
self.view.ui.email_label.setText(EMAIL1_ENTRY)
250
self.view.ui.confirm_email_label.setText(EMAIL2_ENTRY)
251
self.view.ui.password_label.setText(PASSWORD1_ENTRY)
252
self.view.ui.confirm_password_label.setText(PASSWORD2_ENTRY)
253
self.view.ui.password_info_label.setText(PASSWORD_HELP)
254
self.view.ui.captcha_solution_edit.setPlaceholderText(
255
CAPTCHA_SOLUTION_ENTRY)
256
self.view.ui.terms_checkbox.setText(
257
YES_TO_TC % {'app_name': self.view.wizard().app_name})
258
self.view.ui.terms_button.setText(TC_BUTTON)
259
self.view.ui.set_up_button.setText(SET_UP_ACCOUNT_BUTTON)
261
def _set_line_edits_validations(self):
262
"""Set the validations to be performed on the edits."""
263
logger.debug('SetUpAccountController._set_line_edits_validations')
264
self.view.set_line_edit_validation_rule(self.view.ui.email_edit,
266
# set the validation rule for the email confirmation
267
self.view.set_line_edit_validation_rule(
268
self.view.ui.confirm_email_edit,
269
self.is_correct_email_confirmation)
270
# connect the changed text of the password to trigger a changed text
271
# in the confirm so that the validation is redone
272
self.view.ui.email_edit.textChanged.connect(
273
self.view.ui.confirm_email_edit.textChanged.emit)
274
self.view.set_line_edit_validation_rule(self.view.ui.password_edit,
275
is_min_required_password)
276
self.view.set_line_edit_validation_rule(
277
self.view.ui.confirm_password_edit,
278
self.is_correct_password_confirmation)
279
# same as the above case, lets connect a signal to a signal
280
self.view.ui.password_edit.textChanged.connect(
281
self.view.ui.confirm_password_edit.textChanged.emit)
283
def _connect_ui_elements(self):
284
"""Set the connection of signals."""
285
logger.debug('SetUpAccountController._connect_ui_elements')
286
self.view.ui.terms_button.clicked.connect(self.set_next_tos)
287
self.view.ui.set_up_button.clicked.connect(self.set_next_validation)
288
self.view.ui.terms_checkbox.stateChanged.connect(
289
self.view.ui.set_up_button.setEnabled)
290
self.view.ui.refresh_label.linkActivated.connect(lambda url: \
291
self._refresh_captcha())
292
# set the callbacks for the captcha generation
293
self.backend.on_captcha_generated_cb = self.on_captcha_generated
294
self.backend.on_captcha_generation_error_cb = lambda app, error: \
295
self.on_captcha_generation_error(error)
296
self.backend.on_user_registered_cb = self.on_user_registered
297
self.backend.on_user_registration_error_cb = \
298
self.on_user_registration_error
300
def _refresh_captcha(self):
301
"""Refresh the captcha image shown in the ui."""
302
logger.debug('SetUpAccountController._refresh_captcha')
303
# lets clean behind us, do we have the old file arround?
305
if self.view.captcha_file and os.path.exists(self.view.captcha_file):
306
old_file = self.view.captcha_file
307
fd = tempfile.TemporaryFile(mode='r')
309
self.view.captcha_file = file_name
310
d = self.backend.generate_captcha(self.view.wizard().app_name,
313
d.addCallback(lambda x: os.unlink(old_file))
314
d.addErrback(self.on_captcha_generation_error)
316
def _set_titles(self):
317
"""Set the diff titles of the view."""
318
logger.debug('SetUpAccountController._set_titles')
319
wizard = self.view.wizard()
320
self.view.setTitle(JOIN_HEADER_LABEL % {'app_name': wizard.app_name})
321
self.view.setSubTitle(wizard.help_text)
323
def _register_fields(self):
324
"""Register the diff fields of the Ui."""
325
self.view.registerField('email_address', self.view.ui.email_edit)
326
self.view.registerField('password', self.view.ui.password_edit)
328
def on_captcha_generated(self, app_name, result):
329
"""A new image was generated."""
330
logger.debug('SetUpAccountController.on_captcha_generated')
331
self.view.captcha_id = result
332
# HACK: First, let me apologize before hand, you can mention my mother
333
# if needed I would do the same (mandel)
334
# In an ideal world we could use the Qt plug-in for the images so that
335
# we could load jpgs etc.. but this won't work when the app has been
336
# brozen win py2exe using bundle_files=1
337
# The main issue is that Qt will complain about the thread not being
338
# the correct one when performing a moveToThread operation which is
339
# done either by a setParent or something within the qtreactor, PIL
340
# in this case does solve the issue. Sorry :(
341
pil_image = Image.open(self.view.captcha_file)
342
string_io = StringIO.StringIO()
343
pil_image.save(string_io, format='png')
344
pixmap_image = QPixmap()
345
pixmap_image.loadFromData(string_io.getvalue())
346
self.view.captcha_image = pixmap_image
348
def on_captcha_generation_error(self, error):
349
"""An error ocurred."""
350
logger.debug('SetUpAccountController.on_captcha_generation_error')
351
self.message_box.critical(self.view, self.view.wizard().app_name,
354
def on_user_registration_error(self, app_name, error):
355
"""Let the user know we could not register."""
356
logger.debug('SetUpAccountController.on_user_registration_error')
357
# errors are returned as a dict with the data we want to show.
358
self._refresh_captcha()
359
errors = [v for _, v in sorted(error.iteritems())]
360
self.message_box.critical(
362
self.view.wizard().app_name,
365
def on_user_registered(self, app_name, result):
366
"""Execute when the user did register."""
367
logger.debug('SetUpAccountController.on_user_registered')
368
self.view.next = self.view.wizard().email_verification_page_id
369
self.view.wizard().next()
371
def set_next_tos(self):
372
"""Set the tos page as the next one."""
373
logger.debug('SetUpAccountController.set_next_tos')
374
self.view.next = self.view.wizard().tos_page_id
375
self.view.wizard().next()
377
def validate_form(self):
378
"""Validate the info of the form and return an error."""
379
logger.debug('SetUpAccountController.validate_form')
380
email = str(self.view.ui.email_edit.text())
381
confirm_email = str(self.view.ui.confirm_email_edit.text())
382
password = str(self.view.ui.password_edit.text())
383
confirm_password = str(self.view.ui.confirm_password_edit.text())
384
if not is_correct_email(email):
385
self.message_box.critical(self.view, self.view.wizard().app_name,
387
if email != confirm_email:
388
self.message_box.critical(self.view, self.view.wizard().app_name,
391
if not is_min_required_password(password):
392
self.message_box.critical(self.view, self.view.wizard().app_name,
395
if password != confirm_password:
396
self.message_box.critical(self.view, self.view.wizard().app_name,
401
def set_next_validation(self):
402
"""Set the validation as the next page."""
403
logger.debug('SetUpAccountController.set_next_validation')
404
email = str(self.view.ui.email_edit.text())
405
password = str(self.view.ui.password_edit.text())
406
name = str(self.view.ui.name_edit.text())
407
captcha_id = self.view.captcha_id
408
captcha_solution = str(self.view.ui.captcha_solution_edit.text())
409
# validate the current info of the form, try to perform the action
410
# to register the user, and then move foward
411
if self.validate_form():
412
self.backend.register_user(self.view.wizard().app_name, email,
413
password, name, captcha_id,
415
# Update validation page's title, which contains the email
416
p_id = self.view.wizard().email_verification_page_id
417
self.view.wizard().page(p_id).controller.set_titles()
419
def is_correct_email(self, email_address):
420
"""Return if the email is correct."""
421
logger.debug('SetUpAccountController.is_correct_email')
422
return '@' in email_address
424
def is_correct_email_confirmation(self, email_address):
425
"""Return that the email is the same."""
426
logger.debug('SetUpAccountController.is_correct_email_confirmation')
427
return self.view.ui.email_edit.text() == email_address
429
def is_correct_password_confirmation(self, password):
430
"""Return that the passwords are correct."""
431
logger.debug('SetUpAccountController.is_correct_password_confirmation')
432
return self.view.ui.password_edit.text() == password
434
#pylint: disable=C0103
436
def setupUi(self, view):
437
"""Setup the view."""
439
# request the backend to be used with the ui
440
self.backend = yield self.get_backend()
441
self._connect_ui_elements()
442
self._refresh_captcha()
444
self._set_translated_strings()
445
self._set_line_edits_validations()
446
self._register_fields()
447
#pylint: enable=C0103
450
class TosController(object):
451
"""Controller used for the tos page."""
453
def __init__(self, title='', subtitle='', tos_url=''):
454
"""Create a new instance."""
457
self._subtitle = subtitle
458
self._tos_url = tos_url
460
#pylint: disable=C0103
461
def setupUi(self, view):
464
self.view.setTitle(self._title)
465
self.view.setSubTitle(self._subtitle)
467
self.view.ui.terms_webkit.load(QUrl(self._tos_url))
468
self.view.ui.tos_link_label.setText(
470
{'url': self._tos_url})
471
#pylint: enable=C0103
474
class EmailVerificationController(BackendController):
475
"""Controller used for the verification page."""
477
def _set_translated_strings(self):
478
"""Set the trnaslated strings."""
479
logger.debug('EmailVerificationController._set_translated_strings')
480
self.view.ui.verification_code_edit.setPlaceholderText(
483
def _connect_ui_elements(self):
484
"""Set the connection of signals."""
485
logger.debug('EmailVerificationController._connect_ui_elements')
486
self.view.next_button.clicked.connect(self.validate_email)
487
self.backend.on_email_validated_cb = lambda app, result: \
488
self.on_email_validated(app)
489
self.backend.on_email_validation_error_cb = \
490
self.on_email_validation_error
492
def _set_titles(self):
493
"""Set the different titles."""
494
logger.debug('EmailVerificationController._set_titles')
495
self.view.setTitle(VERIFY_EMAIL_TITLE)
496
self.view.setSubTitle(VERIFY_EMAIL_CONTENT % {
497
"app_name": self.view.wizard().app_name,
498
"email": self.view.wizard().field("email_address").toString(),
501
def set_titles(self):
502
"""This class needs to have a public set_titles.
504
Since the subtitle contains data that is only known after SetupAccount
505
and _set_titles is only called on initialization.
509
#pylint: disable=C0103
511
def setupUi(self, view):
512
"""Setup the view."""
514
self.backend = yield self.get_backend()
516
self._set_translated_strings()
517
self._connect_ui_elements()
518
#pylint: enable=C0103
520
def validate_email(self):
521
"""Call the next action."""
522
logger.debug('EmailVerificationController.validate_email')
523
email = str(self.view.wizard().field('email_address').toString())
524
password = str(self.view.wizard().field('password').toString())
525
code = str(self.view.ui.verification_code_edit.text())
526
self.backend.validate_email(self.view.wizard().app_name, email,
529
def on_email_validated(self, app_name):
530
"""Signal thrown after the email is validated."""
531
logger.info('EmailVerificationController.on_email_validated')
532
email = self.view.wizard().field('email_address').toString()
533
self.view.wizard().registrationSuccess.emit(app_name, email)
535
def on_email_validation_error(self, app_name, raised_error):
536
"""Signal thrown when there's a problem validating the email."""
539
class ErrorController(object):
540
"""Controller used for the error page."""
543
"""Create a new instance."""
544
super(ErrorController, self).__init__()
547
#pylint: disable=C0103
548
def setupUi(self, view):
549
"""Setup the view."""
552
self.view.ui.error_message_label.setText(ERROR)
553
#pylint: enable=C0103
556
class ForgottenPasswordController(BackendController):
557
"""Controller used to deal with the forgotten pwd page."""
560
"""Create a new instance."""
561
super(ForgottenPasswordController, self).__init__()
563
def _register_fields(self):
564
"""Register the fields of the wizard page."""
565
self.view.registerField('email_address',
566
self.view.email_address_line_edit)
568
def _set_translated_strings(self):
569
"""Set the translated strings in the view."""
570
self.view.forgotted_password_intro_label.setText(
571
REQUEST_PASSWORD_TOKEN_LABEL % {'app_name':
572
self.view.wizard().app_name})
573
self.view.email_address_label.setText(EMAIL_LABEL)
574
self.view.send_button.setText(RESET_PASSWORD)
575
self.view.try_again_button.setText(TRY_AGAIN_BUTTON)
577
def _set_enhanced_line_edit(self):
578
"""Set the extra logic to the line edits."""
579
self.view.set_line_edit_validation_rule(
580
self.view.email_address_line_edit,
583
def _connect_ui(self):
584
"""Connect the diff signals from the Ui."""
585
self.view.send_button.clicked.connect(
586
lambda: self.backend.request_password_reset_token(
587
self.view.wizard().app_name,
588
self.view.email_address))
589
self.view.try_again_button.clicked.connect(self.on_try_again)
590
# set the backend callbacks to be used
591
self.backend.on_password_reset_token_sent_cb = lambda app, result:\
592
self.on_password_reset_token_sent()
593
self.backend.on_password_reset_error_cb = self.on_password_reset_error
595
def on_try_again(self):
596
"""Set back the widget to the initial state."""
597
self.view.error_label.setVisible(False)
598
self.view.try_again_widget.setVisible(False)
599
self.view.email_widget.setVisible(True)
601
def on_password_reset_token_sent(self):
602
"""Action taken when we managed to get the password reset done."""
603
# ignore the result and move to the reset page
604
self.view.next = self.view.wizard().reset_password_page_id
605
self.view.wizard().next()
607
def on_password_reset_error(self, app_name, error):
608
"""Action taken when there was an error requesting the reset."""
609
if error['errtype'] == 'ResetPasswordTokenError':
610
# the account provided is wrong, lets tell the user to try
612
self.view.error_label.setText(REQUEST_PASSWORD_TOKEN_WRONG_EMAIL)
613
self.view.error_label.setVisible(True)
615
# ouch, I dont know what went wrong, tell the user to try later
616
self.view.email_widget.setVisible(False)
617
self.view.forgotted_password_intro_label.setVisible(False)
618
self.view.try_again_wisget.setVisible(True)
619
# set the error message
620
self.view.error_label.setText(REQUEST_PASSWORD_TOKEN_TECH_ERROR)
622
#pylint: disable=C0103
624
def setupUi(self, view):
625
"""Setup the view."""
627
self.backend = yield self.get_backend()
628
# hide the error label
629
self.view.error_label.setVisible(False)
630
self.view.try_again_widget.setVisible(False)
631
self._set_translated_strings()
633
self._set_enhanced_line_edit()
634
self._register_fields()
635
#pylint: enable=C0103
638
class ResetPasswordController(BackendController):
639
"""Controller used to deal with reseintg the password."""
642
"""Create a new instance."""
643
super(ResetPasswordController, self).__init__()
645
def _set_translated_strings(self):
646
"""Translate the diff strings used in the app."""
647
self.view.ui.reset_code_line_edit.setPlaceholderText(RESET_CODE_ENTRY)
648
self.view.ui.password_line_edit.setPlaceholderText(PASSWORD1_ENTRY)
649
self.view.ui.confirm_password_line_edit.setPlaceholderText(
651
self.view.ui.reset_password_button.setText(RESET_PASSWORD)
652
self.view.setSubTitle(PASSWORD_HELP)
654
def _connect_ui(self):
655
"""Connect the different ui signals."""
656
self.view.ui.reset_password_button.clicked.connect(
657
self.set_new_password)
658
self.backend.on_password_changed_cb = self.on_password_changed
659
self.backend.on_password_change_error_cb = \
660
self.on_password_change_error
662
def _add_line_edits_validations(self):
663
"""Add the validations to be use by the line edits."""
664
self.view.set_line_edit_validation_rule(
665
self.view.ui.password_line_edit,
666
is_min_required_password)
667
self.view.set_line_edit_validation_rule(
668
self.view.ui.confirm_password_line_edit,
669
self.is_correct_password_confirmation)
670
# same as the above case, lets connect a signal to a signal
671
self.view.ui.password_line_edit.textChanged.connect(
672
self.view.ui.confirm_password_line_edit.textChanged.emit)
674
def on_password_changed(self, app_name, result):
675
"""Let user know that the password was changed."""
677
def on_password_change_error(self, app_name, error):
678
"""Let the user know that there was an error."""
680
def set_new_password(self):
681
"""Request a new password to be set."""
682
app_name = self.view.wizard().app_name
683
email = str(self.view.wizard().field('email_address').toString())
684
code = str(self.view.ui.reset_code_line_edit.text())
685
password = str(self.view.ui.password_line_edit.text())
686
logger.info('Settig new password for %s and email %s with code %s',
687
app_name, email, code)
688
self.backend.set_new_password(app_name, email, code, password)
690
def is_correct_password_confirmation(self, password):
691
"""Return if the password is correct."""
692
return self.view.ui.password_line_edit.text() == password
694
#pylint: disable=C0103
696
def setupUi(self, view):
697
"""Setup the view."""
699
self.backend = yield self.get_backend()
700
self._set_translated_strings()
702
self._add_line_edits_validations()
703
#pylint: enable=C0103
706
class SuccessController(object):
707
"""Controller used for the success page."""
710
"""Create a new instance."""
713
#pylint: disable=C0103
714
def setupUi(self, view):
715
"""Setup the view."""
718
self.view.ui.success_message_label.setText(SUCCESS)
719
#pylint: enable=C0103
722
class UbuntuSSOWizardController(object):
723
"""Controller used for the overall wizard."""
725
def __init__(self, login_success_callback=NO_OP,
726
registration_success_callback=NO_OP,
727
user_cancellation_callback=NO_OP):
728
"""Create a new instance."""
730
self.login_success_callback = login_success_callback
731
self.registration_success_callback = registration_success_callback
732
self.user_cancellation_callback = user_cancellation_callback
734
def on_user_cancelation(self):
735
"""Process the cancel action."""
736
logger.debug('UbuntuSSOWizardController.on_user_cancelation')
737
self.user_cancellation_callback(self.view.app_name)
741
def on_login_success(self, app_name, email):
742
"""Process the success of a login."""
743
logger.debug('UbuntuSSOWizardController.on_login_success')
744
result = yield self.login_success_callback(str(app_name), str(email))
745
logger.debug('Result from callback is %s', result)
747
logger.info('Success in calling the given success_callback')
748
self.show_success_message()
750
logger.info('Error in calling the given success_callback')
751
self.show_error_message()
754
def on_registration_success(self, app_name, email):
755
"""Process the success of a registration."""
756
logger.debug('UbuntuSSOWizardController.on_registration_success')
757
result = yield self.registration_success_callback(str(app_name),
760
logger.debug('Result from callback is %s', result)
762
logger.info('Success in calling the given registration_callback')
763
self.show_success_message()
765
logger.info('Success in calling the given registration_callback')
766
self.show_error_message()
768
def show_success_message(self):
769
"""Show the success message in the view."""
770
logger.info('Showing success message.')
771
# get the id of the success page, set it as the next id of the
772
# current page and let the wizard move to the next step
773
self.view.currentPage().next = self.view.success_page_id
775
# show the finish button but with a close message
777
buttons_layout.append(QWizard.Stretch)
778
buttons_layout.append(QWizard.FinishButton)
779
self.view.setButtonLayout(buttons_layout)
781
def show_error_message(self):
782
"""Show the error page in the view."""
783
logger.info('Showing error message.')
784
# similar to the success page but using the error id
785
self.view.currentPage().next = self.view.error_page_id
787
# show the finish button but with a close message
789
buttons_layout.append(QWizard.Stretch)
790
buttons_layout.append(QWizard.FinishButton)
791
self.view.setButtonLayout(buttons_layout)
793
#pylint: disable=C0103
794
def setupUi(self, view):
795
"""Setup the view."""
797
self.view.setWizardStyle(QWizard.ModernStyle)
798
self.view.button(QWizard.CancelButton).clicked.connect(
799
self.on_user_cancelation)
800
self.view.loginSuccess.connect(self.on_login_success)
801
self.view.registrationSuccess.connect(self.on_registration_success)
802
#pylint: enable=C0103