Merge lp:~mandel/ubuntu-sso-client/error_message_style_and_image into lp:ubuntu-sso-client

Proposed by Manuel de la Peña
Status: Merged
Approved by: Roberto Alsina
Approved revision: 777
Merged at revision: 706
Proposed branch: lp:~mandel/ubuntu-sso-client/error_message_style_and_image
Merge into: lp:ubuntu-sso-client
Prerequisite: lp:~mandel/ubuntu-sso-client/success_message
Diff against target: 431 lines (+196/-15)
7 files modified
.bzrignore (+1/-0)
data/qt/error_message.ui (+31/-0)
setup.py (+3/-3)
ubuntu_sso/qt/controllers.py (+51/-4)
ubuntu_sso/qt/gui.py (+41/-7)
ubuntu_sso/qt/tests/test_qt_views.py (+28/-0)
ubuntu_sso/qt/tests/test_windows.py (+41/-1)
To merge this branch: bzr merge lp:~mandel/ubuntu-sso-client/error_message_style_and_image
Reviewer Review Type Date Requested Status
Roberto Alsina (community) Approve
Shane Fagan (community) Approve
Review via email: mp+56712@code.launchpad.net

Commit message

Fixes lp:751496

When working with py2exe and pyqt error will be raised in a Qt plugin is used such as the one that provides support for JPEG images. In order to fix that an new dependency PIL has be added on the Windows side (This issue will not occur on KDE) that allows to convert the captcha image from jpg to png so that we can used the Qt native support.

Fixes lp:751572

Added an error page to be shown when there was an issue in the final step of the process.

Fixes lp:752334

The Wizard controller set the style of the Wizard to be the correct one. Since it is done in the controller this will not affect KDE users.

Fixes lp:752367

Pass the app_name that was forgotten.

Description of the change

Fixes lp:751496

When working with py2exe and pyqt error will be raised in a Qt plugin is used such as the one that provides support for JPEG images. In order to fix that an new dependency PIL has be added on the Windows side (This issue will not occur on KDE) that allows to convert the captcha image from jpg to png so that we can used the Qt native support. Since the plugin are not longer needed the setup dont longer provide them.

Fixes lp:751572

Added an error page to be shown when there was an issue in the final step of the process.

Fixes lp:752334

The Wizard controller set the style of the Wizard to be the correct one. Since it is done in the controller this will not affect KDE users.

Fixes lp:752367

Pass the app_name that was forgotten.

To post a comment you must log in.
Revision history for this message
Shane Fagan (shanepatrickfagan) wrote :

+1 passes tests and I cant see any mistakes in spelling

review: Approve
Revision history for this message
Roberto Alsina (ralsina) wrote :

+1

review: Approve
Revision history for this message
Ubuntu One Auto Pilot (otto-pilot) wrote :
Revision history for this message
Ubuntu One Auto Pilot (otto-pilot) wrote :

Attempt to merge into lp:ubuntu-sso-client failed due to conflicts:

text conflict in setup.py
text conflict in ubuntu_sso/qt/controllers.py
text conflict in ubuntu_sso/qt/gui.py
text conflict in ubuntu_sso/qt/tests/test_windows.py

Revision history for this message
Ubuntu One Auto Pilot (otto-pilot) wrote :

There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.

Revision history for this message
Ubuntu One Auto Pilot (otto-pilot) wrote :
Download full text (43.6 KiB)

The attempt to merge lp:~mandel/ubuntu-sso-client/error_message_style_and_image into lp:ubuntu-sso-client failed. Below is the output from the failed tests.

Running test suite for ubuntu_sso
Xlib: extension "RANDR" missing on display ":99".
ubuntu_sso.utils.tests.test_ui
  GetPasswordStrengTestCase
    test_eight_chars_and_num ... [OK]
    test_eight_chars_low_and_cap ... [OK]
    test_eight_chars_low_canp_num ... [OK]
    test_eight_chars_password ... [OK]
    test_eiqgh_chars_and_special ... [OK]
    test_eleven_chars_and_num ... [OK]
    test_eleven_chars_low_cap ... [OK]
    test_eleven_num_low_cap ... [OK]
    test_eleven_num_special ... [OK]
    test_long_password ... [OK]
    test_small_password ... [OK]
    test_too_small_password ... [OK]
  IsMinRequiredPasswordTestCase
    test_correct_password ... [OK]
    test_no_enough_chars ... [OK]
    test_no_number ... [OK]
    test_no_uppercase ... [OK]
ubuntu_sso.utils.tests.test_txsecrets
  BaseTestCase
    runTest ... [OK]
  CollectionTestCase
    test_create_item ... [OK]
    test_create_item_prompt ... [OK]
    test_create_item_prompt_dismissed ... [OK]
    test_create_item_throws_dbus_error ... [OK]
    test_get_label ... [OK]
ubuntuone.devtools.testcase
  DBusTestCase
    runTest ... [OK]
ubuntu_sso.utils.tests.test_txsecrets
  ItemTestCase
    test_delete ... [OK]
    test_delete_prompt ... [OK]
    test_delete_prompt_dismissed ... [OK]
    test_delete_throws_dbus_error ... [OK]
    test_get_value ... [OK]
    test_get_value_four_items_per_secret ... [OK]
    test_get_value_throws_dbus_error ... [OK]
  SecretServiceTestCase
    test_create_collection ... [OK]
    test_create_collection_prompt ... [OK]
    test_create_collection_prompt_dismissed ... [OK]
    test_create_collection_throw...

777. By Manuel de la Peña

Removed duplicated method.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2011-04-06 09:02:15 +0000
3+++ .bzrignore 2011-04-14 14:56:32 +0000
4@@ -11,3 +11,4 @@
5 ubuntu_sso/qt/setup_account_ui.py
6 ubuntu_sso/qt/terms_and_conditions_ui.py
7 ubuntu_sso/qt/success_message_ui.py
8+ubuntu_sso/qt/error_message_ui.py
9
10=== added file 'data/qt/error_message.ui'
11--- data/qt/error_message.ui 1970-01-01 00:00:00 +0000
12+++ data/qt/error_message.ui 2011-04-14 14:56:32 +0000
13@@ -0,0 +1,31 @@
14+<?xml version="1.0" encoding="UTF-8"?>
15+<ui version="4.0">
16+ <class>ErrorPage</class>
17+ <widget class="QWizardPage" name="ErrorPage">
18+ <property name="geometry">
19+ <rect>
20+ <x>0</x>
21+ <y>0</y>
22+ <width>400</width>
23+ <height>300</height>
24+ </rect>
25+ </property>
26+ <property name="windowTitle">
27+ <string>WizardPage</string>
28+ </property>
29+ <layout class="QVBoxLayout" name="verticalLayout">
30+ <item>
31+ <widget class="QLabel" name="error_message_label">
32+ <property name="text">
33+ <string>TextLabel</string>
34+ </property>
35+ <property name="alignment">
36+ <set>Qt::AlignCenter</set>
37+ </property>
38+ </widget>
39+ </item>
40+ </layout>
41+ </widget>
42+ <resources/>
43+ <connections/>
44+</ui>
45
46=== modified file 'setup.py'
47--- setup.py 2011-04-14 07:59:28 +0000
48+++ setup.py 2011-04-14 14:56:32 +0000
49@@ -334,9 +334,9 @@
50
51 # for PyQt, see http://www.py2exe.org/index.cgi/Py2exeAndPyQt
52 _includes = ['sip', 'email', 'ubuntu_sso.qt.gui',
53- 'ubuntu_sso.qt.controllers', 'PyQt4.QtNetwork']
54- # exclude the modules that are not part of windows, this will not do much
55- # even though the warnings wont be returned.
56+ 'ubuntu_sso.qt.controllers', 'PyQt4.QtNetwork', 'PIL']
57+ # exclude the modules that are not part of widows, this will not do much
58+ # besides the fact that the warnings wont be returned.
59 _excludes = ['dbus', 'dbus.mainloop.glib', 'osx_keychain', 'gobject',
60 'gnomekeyring']
61 # Qt4 plugins, see http://stackoverflow.com/questions/2206406/
62
63=== modified file 'ubuntu_sso/qt/controllers.py'
64--- ubuntu_sso/qt/controllers.py 2011-04-14 07:59:28 +0000
65+++ ubuntu_sso/qt/controllers.py 2011-04-14 14:56:32 +0000
66@@ -17,9 +17,11 @@
67 """Controllers with the logic of the UI."""
68
69 import os
70+import StringIO
71 import tempfile
72
73-from PyQt4.QtGui import QMessageBox, QWizard
74+from PIL import Image
75+from PyQt4.QtGui import QMessageBox, QWizard, QPixmap
76 from PyQt4.QtCore import QUrl
77 from twisted.internet.defer import inlineCallbacks, returnValue
78
79@@ -32,6 +34,7 @@
80 EMAIL2_ENTRY,
81 EMAIL_MISMATCH,
82 EMAIL_INVALID,
83+ ERROR,
84 EXISTING_ACCOUNT_CHOICE_BUTTON,
85 FORGOTTEN_PASSWORD_BUTTON,
86 JOIN_HEADER_LABEL,
87@@ -55,7 +58,6 @@
88
89
90 logger = setup_logging('ubuntu_sso.controllers')
91-
92 # pylint: disable=W0511
93 # disabled warnings about TODO comments
94
95@@ -227,7 +229,8 @@
96 view.confirm_password_edit.setPlaceholderText(PASSWORD2_ENTRY)
97 view.password_info_label.setText(PASSWORD_HELP)
98 view.captcha_solution_edit.setPlaceholderText(CAPTCHA_SOLUTION_ENTRY)
99- view.terms_and_conditions_check_box.setText(YES_TO_TC)
100+ view.terms_and_conditions_check_box.setText(
101+ YES_TO_TC % {'app_name': self._app_name})
102 view.terms_and_conditions_button.setText(TC_BUTTON)
103 view.set_up_button.setText(SET_UP_ACCOUNT_BUTTON)
104
105@@ -301,7 +304,22 @@
106 def on_captcha_generated(self, view, app_name, result):
107 """A new image was generated."""
108 logger.debug('SetUpAccountController.on_captcha_generated')
109- view.captcha_image = result
110+ view.captcha_id = result
111+ # HACK: First, let me apologize before hand, you can mention my mother
112+ # if needed I would do the same (mandel)
113+ # In an ideal world we could use the Qt plug-in for the images so that
114+ # we could load jpgs etc.. but this won't work when the app has been
115+ # frozen win py2exe using bundle_files=1
116+ # The main issue is that Qt will complain about the thread not being
117+ # the correct one when performing a moveToThread operation which is
118+ # done either by a setParent or something within the qtreactor, PIL
119+ # in this case does solve the issue. Sorry :(
120+ pil_image = Image.open(view.captcha_file)
121+ string_io = StringIO.StringIO()
122+ pil_image.save(string_io, format='png')
123+ pixmap_image = QPixmap()
124+ pixmap_image.loadFromData(string_io.getvalue())
125+ view.captcha_image = pixmap_image
126
127 def on_captcha_generation_error(self, view, app_name, error):
128 """An error ocurred."""
129@@ -442,6 +460,20 @@
130 view.wizard().next()
131
132
133+class ErrorController(object):
134+ """Controller used for the error page."""
135+
136+ def __init__(self):
137+ """Create a new instance."""
138+
139+ #pylint: disable=C0103
140+ def setupUi(self, view):
141+ """Setup the view."""
142+ view.next = -1
143+ view.error_message_label.setText(ERROR)
144+ #pylint: enable=C0103
145+
146+
147 class SuccessController(object):
148 """Controller used for the success page."""
149
150@@ -485,6 +517,7 @@
151 self.show_success_message(view)
152 else:
153 logger.info('Error in calling the given success_callback')
154+ self.show_error_message(view)
155
156 @inlineCallbacks
157 def on_registration_success(self, app_name, email, view):
158@@ -498,6 +531,19 @@
159 self.show_success_message(view)
160 else:
161 logger.info('Success in calling the given registration_callback')
162+ self.show_error_message(view)
163+
164+ def show_error_message(self, view):
165+ """Show the error page in the view."""
166+ logger.info('Showing error message.')
167+ # similar to the success page but using the error id
168+ view.currentPage().next = view.error_page_id
169+ view.next()
170+ # show the finish button but with a close message
171+ buttons_layout = []
172+ buttons_layout.append(QWizard.Stretch)
173+ buttons_layout.append(QWizard.FinishButton)
174+ view.setButtonLayout(buttons_layout)
175
176 def show_success_message(self, view):
177 """Show the success message in the view."""
178@@ -515,6 +561,7 @@
179 #pylint: disable=C0103
180 def setupUi(self, view):
181 """Setup the view."""
182+ view.setWizardStyle(QWizard.ModernStyle)
183 view.button(QWizard.CancelButton).clicked.connect(
184 lambda: self.on_user_cancelation(view))
185 view.loginSuccess.connect(
186
187=== modified file 'ubuntu_sso/qt/gui.py'
188--- ubuntu_sso/qt/gui.py 2011-04-14 07:59:28 +0000
189+++ ubuntu_sso/qt/gui.py 2011-04-14 14:56:32 +0000
190@@ -34,6 +34,7 @@
191 from ubuntu_sso.qt.choose_sign_in_ui import Ui_ChooseSignInPage
192 from ubuntu_sso.qt.current_user_sign_in_ui import Ui_CurrentUserSignInPage
193 from ubuntu_sso.qt.email_verification_ui import Ui_EmailVerificationPage
194+from ubuntu_sso.qt.error_message_ui import Ui_ErrorPage
195 from ubuntu_sso.qt.setup_account_ui import Ui_SetUpAccountPage
196 from ubuntu_sso.qt.terms_and_conditions_ui import Ui_TosPage
197 from ubuntu_sso.qt.success_message_ui import Ui_SuccessPage
198@@ -42,6 +43,7 @@
199 ChooseSignInController,
200 CurrentUserController,
201 EmailVerificationController,
202+ ErrorController,
203 SetUpAccountController,
204 SuccessController,
205 TosController,
206@@ -156,6 +158,30 @@
207 return self.ui.next_button
208
209
210+class ErrorPage(QWizardPage):
211+ """Widget used to show the diff errors."""
212+
213+ def __init__(self, ui, controller, parent=None):
214+ """Create a new widget to be used."""
215+ QWizardPage.__init__(self, parent)
216+ self.ui = ui
217+ self.ui.setupUi(self)
218+ self.controller = controller
219+ self.controller.setupUi(self)
220+ self.next = -1
221+
222+ # pylint: disable=C0103
223+ def nextId(self):
224+ """Return the next page id."""
225+ return self.next
226+ # pylint: enable=C0103
227+
228+ @property
229+ def error_message_label(self):
230+ """Return the label used to show the error."""
231+ return self.ui.error_message_label
232+
233+
234 class TosPage(QWizardPage):
235 """Widget used to show the tos."""
236
237@@ -229,6 +255,7 @@
238 self.next = -1
239 self.captcha_id = None
240 self.captcha_file = None
241+ self.ui.captcha_view.setPixmap(QPixmap())
242 self.controller = controller
243 self.controller.setupUi(self)
244
245@@ -364,14 +391,12 @@
246
247 def get_captcha_image(self):
248 """Return the path to the captcha image."""
249- return self.captcha_id
250+ return self.ui.captcha_view.pixmap()
251
252- def set_captcha_image(self, data):
253+ def set_captcha_image(self, pixmap_image):
254 """Set the new image of the captcha."""
255- self.captcha_id = data
256 # lets set the QPixmap for the label
257- pic = QPixmap(self.captcha_file)
258- self.ui.captcha_view.setPixmap(pic)
259+ self.ui.captcha_view.setPixmap(pixmap_image)
260
261 captcha_image = property(get_captcha_image, set_captcha_image)
262
263@@ -424,6 +449,7 @@
264 """Wizard used to create or use sso."""
265
266 # definition of the signals raised by the widget
267+ recoverableError = pyqtSignal('QString', 'QString')
268 loginSuccess = pyqtSignal('QString', 'QString')
269 registrationSuccess = pyqtSignal('QString', 'QString')
270
271@@ -457,10 +483,13 @@
272 self.success_controller = SuccessController()
273 self.success = SuccessPage(Ui_SuccessPage(), self.success_controller,
274 parent=self)
275- # store the dis of the pages so that it is easier to access them later
276+ self.error_controller = ErrorController()
277+ self.error = ErrorPage(Ui_ErrorPage(), self.error_controller)
278+ # store the ids of the pages so that it is easier to access them later
279 self._pages = {}
280 for page in [self.sign_in_page, self.setup_account, self.tos,
281- self.email_verification, self.current_user, self.success]:
282+ self.email_verification, self.current_user, self.success,
283+ self.error]:
284 self._pages[page] = self.addPage(page)
285
286 # set the buttons layout to only have cancel and back since the next
287@@ -479,6 +508,11 @@
288 """Return the id of the success page."""
289 return self._pages[self.success]
290
291+ @property
292+ def error_page_id(self):
293+ """Return the id of the error page."""
294+ return self._pages[self.error]
295+
296
297 class UbuntuSSOClientGUI(object):
298 """Ubuntu single sign-on GUI."""
299
300=== modified file 'ubuntu_sso/qt/tests/test_qt_views.py'
301--- ubuntu_sso/qt/tests/test_qt_views.py 2011-03-31 14:38:05 +0000
302+++ ubuntu_sso/qt/tests/test_qt_views.py 2011-04-14 14:56:32 +0000
303@@ -24,6 +24,7 @@
304 ChooseSignInPage,
305 CurrentUserSignInPage,
306 EmailVerificationPage,
307+ ErrorPage,
308 SetupAccountPage,
309 SuccessPage,
310 TosPage)
311@@ -34,6 +35,7 @@
312 from ubuntu_sso.qt.choose_sign_in_ui import Ui_ChooseSignInPage
313 from ubuntu_sso.qt.current_user_sign_in_ui import Ui_CurrentUserSignInPage
314 from ubuntu_sso.qt.email_verification_ui import Ui_EmailVerificationPage
315+from ubuntu_sso.qt.error_message_ui import Ui_ErrorPage
316 from ubuntu_sso.qt.terms_and_conditions_ui import Ui_TosPage
317 from ubuntu_sso.qt.setup_account_ui import Ui_SetUpAccountPage
318 from ubuntu_sso.qt.success_message_ui import Ui_SuccessPage
319@@ -361,3 +363,29 @@
320 """Test that the correct label is returned."""
321 self.assertEqual(self.ui.success_message_label,
322 self.widget.success_message_label)
323+
324+
325+class ErrorPageTestCase(TestCase):
326+ """Test that the correct widgets are used."""
327+
328+ def setUp(self):
329+ """Setup tests."""
330+ super(ErrorPageTestCase, self).setUp()
331+ self.ui = Ui_ErrorPage()
332+ self.controller = FakeController()
333+ self.widget = ErrorPage(self.ui, self.controller)
334+
335+ def test_constructor(self):
336+ """Test that the constructor works as expected."""
337+ mocker = Mocker()
338+ ui = mocker.mock()
339+ controller = mocker.mock()
340+ ui.setupUi(MATCH(lambda x: isinstance(x, ErrorPage)))
341+ controller.setupUi(MATCH(lambda x: isinstance(x, ErrorPage)))
342+ mocker.replay()
343+ self.widget = ErrorPage(self.ui, self.controller)
344+
345+ def test_success_message_label(self):
346+ """Test that the correct label is returned."""
347+ self.assertEqual(self.ui.error_message_label,
348+ self.widget.error_message_label)
349
350=== modified file 'ubuntu_sso/qt/tests/test_windows.py'
351--- ubuntu_sso/qt/tests/test_windows.py 2011-04-14 07:59:28 +0000
352+++ ubuntu_sso/qt/tests/test_windows.py 2011-04-14 14:56:32 +0000
353@@ -23,6 +23,7 @@
354 ChooseSignInController,
355 CurrentUserController,
356 EmailVerificationController,
357+ ErrorController,
358 SetUpAccountController,
359 SuccessController,
360 TosController,
361@@ -32,6 +33,7 @@
362 EMAIL1_ENTRY,
363 EMAIL2_ENTRY,
364 EMAIL_MISMATCH,
365+ ERROR,
366 EXISTING_ACCOUNT_CHOICE_BUTTON,
367 FORGOTTEN_PASSWORD_BUTTON,
368 JOIN_HEADER_LABEL,
369@@ -153,7 +155,8 @@
370 self.view.password_info_label.setText(PASSWORD_HELP)
371 self.view.captcha_solution_edit.setPlaceholderText(
372 CAPTCHA_SOLUTION_ENTRY)
373- self.view.terms_and_conditions_check_box.setText(YES_TO_TC)
374+ self.view.terms_and_conditions_check_box.setText(
375+ YES_TO_TC % {'app_name': self.app_name})
376 self.view.terms_and_conditions_button.setText(TC_BUTTON)
377 self.view.set_up_button.setText(SET_UP_ACCOUNT_BUTTON)
378 self.mocker.replay()
379@@ -421,6 +424,25 @@
380 self.controller.next_page(self.view)
381
382
383+class ErrorControllerTestCase(MockerTestCase):
384+ """Test the success page controller."""
385+
386+ def setUp(self):
387+ """Set the tests."""
388+ super(ErrorControllerTestCase, self).setUp()
389+ self.controller = ErrorController()
390+ self.view = self.mocker.mock()
391+
392+ def test_set_ui(self):
393+ """Test the process that sets the ui."""
394+ self.view.next = -1
395+ self.view.error_message_label
396+ self.mocker.result(self.view)
397+ self.view.setText(ERROR)
398+ self.mocker.replay()
399+ self.controller.setupUi(self.view)
400+
401+
402 class SuccessControllerTestCase(MockerTestCase):
403 """Test the success page controller."""
404
405@@ -494,8 +516,26 @@
406 self.mocker.replay()
407 self.controller.show_success_message(self.view)
408
409+ def test_show_error_message(self):
410+ """Test that the correct page will be shown."""
411+ error_page_id = 0
412+ # the buttons layout we expect to have
413+ buttons_layout = []
414+ buttons_layout.append(QWizard.Stretch)
415+ buttons_layout.append(QWizard.FinishButton)
416+ self.view.error_page_id
417+ self.mocker.result(error_page_id)
418+ self.view.currentPage()
419+ self.mocker.result(self.view)
420+ self.view.next = error_page_id
421+ self.view.next()
422+ self.view.setButtonLayout(buttons_layout)
423+ self.mocker.replay()
424+ self.controller.show_error_message(self.view)
425+
426 def test_setup_ui(self):
427 """Test that the ui is connect."""
428+ self.view.setWizardStyle(QWizard.ModernStyle)
429 self.view.button(QWizard.CancelButton)
430 self.mocker.result(self.view)
431 self.view.clicked.connect(MATCH(callable))

Subscribers

People subscribed via source and target branches