~mvo/ubuntu-sso-client/strawman-lp711413

« back to all changes in this revision

Viewing changes to ubuntu_sso/qt/gui.py

  • Committer: Tarmac
  • Author(s): Manuel de la Pena, ralsina, Roberto Alsina
  • Date: 2011-04-14 17:01:56 UTC
  • mfrom: (705.2.2 forgotten_password)
  • Revision ID: tarmac-20110414170156-4k8s1708gzgj5oi2
Fixes lp:753281

Adds the required UI and backend to allow a windows user to reset his sso password from the Windows client. Tests have been added to ensure that the backend is correctly called.

Show diffs side-by-side

added added

removed removed

Lines of Context:
38
38
from ubuntu_sso.qt.setup_account_ui import Ui_SetUpAccountPage
39
39
from ubuntu_sso.qt.terms_and_conditions_ui import Ui_TosPage
40
40
from ubuntu_sso.qt.success_message_ui import Ui_SuccessPage
 
41
from ubuntu_sso.qt.forgotten_password_ui import Ui_ForgottenPasswordPage
 
42
from ubuntu_sso.qt.reset_password_ui import Ui_ResetPasswordPage
41
43
# pylint: enable=F0401,E0611
42
44
from ubuntu_sso.qt.controllers import (
43
45
    ChooseSignInController,
44
46
    CurrentUserController,
45
47
    EmailVerificationController,
46
48
    ErrorController,
 
49
    ForgottenPasswordController,
 
50
    ResetPasswordController,
47
51
    SetUpAccountController,
48
52
    SuccessController,
49
53
    TosController,
58
62
STRONG_COLOR = QColor(50, 205, 50)
59
63
 
60
64
 
61
 
class ChooseSignInPage(QWizardPage):
 
65
class SSOWizardPage(QWizardPage):
 
66
    """Root class for all wizard pages."""
 
67
 
 
68
    def __init__(self, ui, controller, parent=None):
 
69
        """Create a new instance."""
 
70
        QWizardPage.__init__(self, parent)
 
71
        self.ui = ui
 
72
        self.ui.setupUi(self)
 
73
        self.controller = controller
 
74
        self.controller.setupUi(self)
 
75
        self.next = -1
 
76
 
 
77
    # pylint: disable=C0103
 
78
    def nextId(self):
 
79
        """Provide the next id."""
 
80
        return self.next
 
81
    # pylint: enable=C0103
 
82
 
 
83
 
 
84
class EnhancedLineEdit(object):
 
85
    """Represents and enhanced lineedit.
 
86
 
 
87
    This class works on an already added lineedit to the widget so
 
88
    that we are just adding extra items to it.
 
89
    """
 
90
 
 
91
    def __init__(self, line_edit, valid_cb=lambda x: False):
 
92
        """Create an instance."""
 
93
        self._line_edit = line_edit
 
94
        layout = QHBoxLayout(self._line_edit)
 
95
        layout.setMargin(0)
 
96
        self._line_edit.setLayout(layout)
 
97
        self.valid_cb = valid_cb
 
98
        layout.addStretch()
 
99
        self.clear_button = QPushButton(self._line_edit)
 
100
        layout.addWidget(self.clear_button)
 
101
        self.clear_button.setMinimumSize(16, 16)
 
102
        self.clear_button.setVisible(False)
 
103
        self.clear_button.setFlat(True)
 
104
        self.clear_button.setCursor(QCursor(0))
 
105
        self.clear_button.setIcon(QApplication.style().standardIcon(
 
106
                                                QStyle.SP_MessageBoxWarning))
 
107
        # connect the change of text to the cation that will check if the
 
108
        # text is valid and if the icon should be shown.
 
109
        self._line_edit.textChanged.connect(self.show_button)
 
110
 
 
111
    def show_button(self, string):
 
112
        """Decide if we show the button or not."""
 
113
        if not self.valid_cb(string):
 
114
            self.clear_button.setVisible(True)
 
115
        else:
 
116
            self.clear_button.setVisible(False)
 
117
 
 
118
 
 
119
class SSOWizardEnhancedEditPage(SSOWizardPage):
 
120
    """Page that contains enhanced line edits."""
 
121
 
 
122
    def __init__(self, ui, controller, parent=None):
 
123
        """Create a new instance."""
 
124
        SSOWizardPage.__init__(self, ui, controller, parent)
 
125
        self._enhanced_edits = {}
 
126
 
 
127
    def set_line_edit_validation_rule(self, edit, cb):
 
128
        """Set a new enhanced edit so that we can show an icon."""
 
129
        if edit in self._enhanced_edits:
 
130
            self._enhanced_edits[edit].valid_cb = cb
 
131
        else:
 
132
            # create a new enhanced edit
 
133
            enhanced_edit = EnhancedLineEdit(edit, cb)
 
134
            self._enhanced_edits[edit] = enhanced_edit
 
135
 
 
136
 
 
137
class ChooseSignInPage(SSOWizardPage):
62
138
    """Widget that allows the user to choose how to sign in."""
63
139
 
64
140
    def __init__(self, ui, controller, parent=None):
65
141
        """Create a new widget to be used."""
66
 
        QWizardPage.__init__(self, parent)
67
 
        self.ui = ui
68
 
        self.controller = controller
69
 
        ui.setupUi(self)
70
 
        controller.setupUi(self)
71
 
        self.next = -1
72
 
 
73
 
    # pylint: disable=C0103
74
 
    def nextId(self):
75
 
        """Provide the next id."""
76
 
        return self.next
77
 
    # pylint: enable=C0103
 
142
        SSOWizardPage.__init__(self, ui, controller, parent)
78
143
 
79
144
    # allow to access to the different useful children
80
145
    @property
88
153
        return self.ui.setup_account_button
89
154
 
90
155
 
91
 
class CurrentUserSignInPage(QWizardPage):
 
156
class CurrentUserSignInPage(SSOWizardPage):
92
157
    """Widget that allows to get the data of user to sign in."""
93
158
 
94
159
    def __init__(self, ui, controller, parent=None):
95
160
        """Create a new widget to be used."""
96
 
        QWizardPage.__init__(self, parent)
97
 
        self.ui = ui
98
 
        self.controller = controller
99
 
        self.ui.setupUi(self)
100
 
        self.controller.setupUi(self)
 
161
        SSOWizardPage.__init__(self, ui, controller, parent)
101
162
 
102
163
    # allow to access to the different useful data
103
164
    @property
131
192
        return self.ui.sign_in_button
132
193
 
133
194
 
134
 
class EmailVerificationPage(QWizardPage):
 
195
class EmailVerificationPage(SSOWizardPage):
135
196
    """Widget used to input the email verification code."""
136
197
 
137
198
    def __init__(self, ui, controller, parent=None):
138
199
        """Create a new widget to be used."""
139
 
        QWizardPage.__init__(self, parent)
140
 
        self.ui = ui
141
 
        self.ui.setupUi(self)
142
 
        self.controller = controller
143
 
        self.controller.setupUi(self)
 
200
        SSOWizardPage.__init__(self, ui, controller, parent)
144
201
 
145
202
    @property
146
203
    def verification_code(self):
158
215
        return self.ui.next_button
159
216
 
160
217
 
161
 
class ErrorPage(QWizardPage):
 
218
class ErrorPage(SSOWizardPage):
162
219
    """Widget used to show the diff errors."""
163
220
 
164
221
    def __init__(self, ui, controller, parent=None):
165
222
        """Create a new widget to be used."""
166
 
        QWizardPage.__init__(self, parent)
 
223
        SSOWizardPage.__init__(self, ui, controller, parent)
167
224
        self.ui = ui
168
225
        self.ui.setupUi(self)
169
226
        self.controller = controller
182
239
        return self.ui.error_message_label
183
240
 
184
241
 
185
 
class TosPage(QWizardPage):
 
242
class ForgottenPasswordPage(SSOWizardEnhancedEditPage):
 
243
    """Widget used to deal with users that forgot the password."""
 
244
 
 
245
    def __init__(self, ui, controller, parent=None):
 
246
        """Create a new instance."""
 
247
        SSOWizardEnhancedEditPage.__init__(self, ui, controller, parent)
 
248
 
 
249
    @property
 
250
    def email_widget(self):
 
251
        """Return the widget used to show the email information."""
 
252
        return self.ui.email_widget
 
253
 
 
254
    @property
 
255
    def forgotted_password_intro_label(self):
 
256
        """Return the intro label that lets the user know the issue."""
 
257
        return self.ui.forgotted_password_intro_label
 
258
 
 
259
    @property
 
260
    def error_label(self):
 
261
        """Return the label used to show error."""
 
262
        return self.ui.error_label
 
263
 
 
264
    @property
 
265
    def email_address_label(self):
 
266
        """Return the lable used to state the use of the line edit."""
 
267
        return self.ui.email_address_label
 
268
 
 
269
    @property
 
270
    def email_address(self):
 
271
        """Return the email address provided by the user."""
 
272
        return str(self.ui.email_line_edit.text())
 
273
 
 
274
    @property
 
275
    def email_address_line_edit(self):
 
276
        """Return the line edit with the content."""
 
277
        return self.ui.email_line_edit
 
278
 
 
279
    @property
 
280
    def send_button(self):
 
281
        """Return the button used to request the new password."""
 
282
        return self.ui.send_button
 
283
 
 
284
    @property
 
285
    def try_again_widget(self):
 
286
        """Return the widget used to display the try again button."""
 
287
        return self.ui.try_again_widget
 
288
 
 
289
    @property
 
290
    def try_again_button(self):
 
291
        """Return the button used to try again the reset password."""
 
292
        return self.ui.try_again_button
 
293
 
 
294
 
 
295
class ResetPasswordPage(SSOWizardEnhancedEditPage):
 
296
    """Widget used to allow the user change his password."""
 
297
 
 
298
    def __init__(self, ui, controller, parent=None):
 
299
        """Create a new instance."""
 
300
        SSOWizardEnhancedEditPage.__init__(self, ui, controller, parent)
 
301
 
 
302
    @property
 
303
    def reset_code_line_edit(self):
 
304
        """Return the  line edit where the reset code is given."""
 
305
        return self.ui.reset_code_line_edit
 
306
 
 
307
    @property
 
308
    def reset_code(self):
 
309
        """Return the reset code typed by the user."""
 
310
        return str(self.ui.reset_code_line_edit.text())
 
311
 
 
312
    @property
 
313
    def password_line_edit(self):
 
314
        """Return the line edit where the password is typed."""
 
315
        return self.ui.password_line_edit
 
316
 
 
317
    @property
 
318
    def password(self):
 
319
        """Return the passsword typed by the user."""
 
320
        return str(self.ui.password_line_edit.text())
 
321
 
 
322
    @property
 
323
    def confirm_password_line_edit(self):
 
324
        """Return the line edit used to confirm the password."""
 
325
        return self.ui.confirm_password_line_edit
 
326
 
 
327
    @property
 
328
    def retyped_password(self):
 
329
        """Return the password confirmation given by the user."""
 
330
        return str(self.ui.confirm_password_line_edit.text())
 
331
 
 
332
    @property
 
333
    def reset_password_button(self):
 
334
        """Return the button used to reset the password."""
 
335
        return self.ui.reset_password_button
 
336
 
 
337
 
 
338
class TosPage(SSOWizardPage):
186
339
    """Widget used to show the tos."""
187
340
 
188
341
    def __init__(self, ui, controller, parent=None):
189
342
        """Create a new instance."""
190
 
        QWizardPage.__init__(self, parent)
191
 
        self.ui = ui
192
 
        self.ui.setupUi(self)
193
 
        self.controller = controller
194
 
        self.controller.setupUi(self)
195
 
 
196
 
    # pylint: disable=C0103
197
 
    def nextId(self):
198
 
        """Return the next page id."""
199
 
        return -1
200
 
    # pylint: enable=C0103
 
343
        SSOWizardPage.__init__(self, ui, controller, parent)
201
344
 
202
345
    @property
203
346
    def webkit(self):
205
348
        return self.ui.terms_webkit
206
349
 
207
350
 
208
 
class EnhancedLineEdit(object):
209
 
    """Represents an enhanced lineedit.
210
 
 
211
 
    This class works on an already added lineedit to the widget so
212
 
    that we are just adding extra items to it.
213
 
    """
214
 
 
215
 
    def __init__(self, line_edit, valid_cb=lambda x: False):
216
 
        """Create an instance."""
217
 
        self._line_edit = line_edit
218
 
        layout = QHBoxLayout(self._line_edit)
219
 
        layout.setMargin(0)
220
 
        self._line_edit.setLayout(layout)
221
 
        self.valid_cb = valid_cb
222
 
        layout.addStretch()
223
 
        self.clear_button = QPushButton(self._line_edit)
224
 
        layout.addWidget(self.clear_button)
225
 
        self.clear_button.setMinimumSize(16, 16)
226
 
        self.clear_button.setVisible(False)
227
 
        self.clear_button.setFlat(True)
228
 
        self.clear_button.setCursor(QCursor(0))
229
 
        self.clear_button.setIcon(QApplication.style().standardIcon(
230
 
                                                QStyle.SP_MessageBoxWarning))
231
 
        # connect the change of text to the callback that will check if the
232
 
        # text is valid and if the icon should be shown.
233
 
        self._line_edit.textChanged.connect(self.show_button)
234
 
 
235
 
    def show_button(self, string):
236
 
        """Decide if we show the button or not."""
237
 
        if not self.valid_cb(string):
238
 
            self.clear_button.setVisible(True)
239
 
        else:
240
 
            self.clear_button.setVisible(False)
241
 
 
242
 
 
243
 
class SetupAccountPage(QWizardPage):
 
351
class SetupAccountPage(SSOWizardEnhancedEditPage):
244
352
    """Widget used to create a new account."""
245
353
 
246
354
    def __init__(self, ui, controller, parent=None):
247
355
        """Create a new widget to be used."""
248
 
        QWizardPage.__init__(self, parent)
 
356
        SSOWizardEnhancedEditPage.__init__(self, ui, controller, parent)
249
357
        self._enhanced_edits = {}
250
358
        self.ui = ui
251
359
        self.ui.setupUi(self)
252
360
        # palettes that will be used to set the colors of the password strength
253
361
        original_palette = self.ui.strength_frame.palette()
254
362
        self._original_color = original_palette.background().color()
255
 
        self.next = -1
256
363
        self.captcha_id = None
257
364
        self.captcha_file = None
258
365
        self.ui.captcha_view.setPixmap(QPixmap())
294
401
        frame.setPalette(palette)
295
402
        frame.setAutoFillBackground(True)
296
403
 
297
 
    # pylint: disable=C0103
298
 
    def nextId(self):
299
 
        """Return the next page id."""
300
 
        return self.next
301
 
    # pylint: enable=C0103
302
 
 
303
 
    def set_line_edit_validation_rule(self, edit, cb):
304
 
        """Set a new enhanced edit so that we can show an icon."""
305
 
        if edit in self._enhanced_edits:
306
 
            self._enhanced_edits[edit].valid_cb = cb
307
 
        else:
308
 
            # create a new enhanced edit
309
 
            enhanced_edit = EnhancedLineEdit(edit, cb)
310
 
            self._enhanced_edits[edit] = enhanced_edit
311
 
 
312
404
    @property
313
405
    def name(self):
314
406
        """Return the name input."""
421
513
        return self.ui.set_up_button
422
514
 
423
515
 
424
 
class SuccessPage(QWizardPage):
 
516
class SuccessPage(SSOWizardPage):
425
517
    """Page used to display success message."""
426
518
 
427
519
    def __init__(self, ui, controller, parent=None):
428
520
        """Create a new instance."""
429
 
        QWizardPage.__init__(self, parent)
 
521
        SSOWizardPage.__init__(self, ui, controller, parent)
430
522
        self.ui = ui
431
523
        self.ui.setupUi(self)
432
524
        self.controller = controller
457
549
                 help_text=''):
458
550
        """Create a new wizard."""
459
551
        QWizard.__init__(self, parent)
 
552
        # store common useful data provided by the app
 
553
        self.app_name = app_name
 
554
        self.tos_url = tos_url
 
555
        self.help_text = help_text
 
556
 
460
557
        # set the diff pages of the QWizard
461
 
        self.sign_in_controller = ChooseSignInController(title='Sign In',
462
 
                                                         existing_account_id=4,
463
 
                                                         new_account_id=1)
 
558
        self.sign_in_controller = ChooseSignInController(title='Sign In')
464
559
        self.sign_in_page = ChooseSignInPage(Ui_ChooseSignInPage(),
465
560
                                             self.sign_in_controller,
466
561
                                             parent=self)
467
 
        self.setup_controller = SetUpAccountController(tos_id=2,
468
 
                                                       validation_id=3,
469
 
                                                       app_name=app_name,
470
 
                                                       help_message='')
 
562
        self.setup_controller = SetUpAccountController()
471
563
        self.setup_account = SetupAccountPage(Ui_SetUpAccountPage(),
472
564
                                              self.setup_controller,
473
565
                                              parent=self)
474
 
        self.tos = TosPage(Ui_TosPage(), TosController())
 
566
        self.tos = TosPage(Ui_TosPage(), TosController(tos_url=tos_url),
 
567
                           parent=self)
475
568
        self.email_verification = EmailVerificationPage(
476
569
                                                Ui_EmailVerificationPage(),
477
570
                                                EmailVerificationController())
478
 
        self.current_user_controller = CurrentUserController(title='Sign in',
479
 
                                                            app_name=app_name)
 
571
        self.current_user_controller = CurrentUserController(title='Sign in')
480
572
        self.current_user = CurrentUserSignInPage(Ui_CurrentUserSignInPage(),
481
573
                                                  self.current_user_controller,
482
574
                                                  parent=self)
485
577
                                   parent=self)
486
578
        self.error_controller = ErrorController()
487
579
        self.error = ErrorPage(Ui_ErrorPage(), self.error_controller)
 
580
        self.forgotte_pwd_controller = ForgottenPasswordController()
 
581
        self.forgotten = ForgottenPasswordPage(Ui_ForgottenPasswordPage(),
 
582
                                               self.forgotte_pwd_controller,
 
583
                                               parent=self)
 
584
        self.reset_password_controller = ResetPasswordController()
 
585
        self.reset_password = ResetPasswordPage(Ui_ResetPasswordPage(),
 
586
                                                self.reset_password_controller,
 
587
                                                parent=self)
488
588
        # store the ids of the pages so that it is easier to access them later
489
589
        self._pages = {}
490
590
        for page in [self.sign_in_page, self.setup_account, self.tos,
491
591
                     self.email_verification, self.current_user, self.success,
492
 
                     self.error]:
 
592
                     self.error, self.forgotten, self.reset_password]:
493
593
            self._pages[page] = self.addPage(page)
494
594
 
495
595
        # set the buttons layout to only have cancel and back since the next
504
604
        self.controller.setupUi(self)
505
605
 
506
606
    @property
 
607
    def sign_in_page_id(self):
 
608
        """Return the id of the page used for choosing sign in type."""
 
609
        return self._pages[self.sign_in_page]
 
610
 
 
611
    @property
 
612
    def setup_account_page_id(self):
 
613
        """Return the id of the page used for sign in."""
 
614
        return self._pages[self.setup_account]
 
615
 
 
616
    @property
 
617
    def tos_page_id(self):
 
618
        """Return the id of the tos page."""
 
619
        return self._pages[self.tos]
 
620
 
 
621
    @property
 
622
    def email_verification_page_id(self):
 
623
        """Return the id of the verification page."""
 
624
        return self._pages[self.email_verification]
 
625
 
 
626
    @property
 
627
    def current_user_page_id(self):
 
628
        """Return the id used to signin by a current user."""
 
629
        return self._pages[self.current_user]
 
630
 
 
631
    @property
507
632
    def success_page_id(self):
508
633
        """Return the id of the success page."""
509
634
        return self._pages[self.success]
510
635
 
511
636
    @property
 
637
    def forgotten_password_page_id(self):
 
638
        """Return the id of the forgotten password page."""
 
639
        return self._pages[self.forgotten]
 
640
 
 
641
    @property
 
642
    def reset_password_page_id(self):
 
643
        """Return the id of the reset password page."""
 
644
        return self._pages[self.reset_password]
 
645
 
 
646
    @property
512
647
    def error_page_id(self):
513
648
        """Return the id of the error page."""
514
649
        return self._pages[self.error]
517
652
class UbuntuSSOClientGUI(object):
518
653
    """Ubuntu single sign-on GUI."""
519
654
 
520
 
    def __init__(self, app_name, tc_url='', help_text='',
 
655
    def __init__(self, app_name, tc_url='http://one.ubuntu.com', help_text='',
521
656
                 window_id=0, login_only=False):
522
657
        """Create a new instance."""
523
658
        # create the controller and the ui, then set the cb and call the show