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

Proposed by Manuel de la Peña
Status: Merged
Approved by: Manuel de la Peña
Approved revision: 746
Merged at revision: 695
Proposed branch: lp:~mandel/ubuntu-sso-client/windows_ui_3
Merge into: lp:ubuntu-sso-client
Prerequisite: lp:~mandel/ubuntu-sso-client/windows_ui_1
Diff against target: 2481 lines (+1634/-597)
11 files modified
data/qt/choose_sign_in.ui (+7/-7)
data/qt/current_user_sign_in.ui (+35/-82)
data/qt/email_verification.ui (+6/-31)
data/qt/setup_account.ui (+347/-442)
data/qt/terms_and_conditions.ui (+5/-35)
ubuntu_sso/qt/controllers.py (+260/-0)
ubuntu_sso/qt/gui.py (+438/-0)
ubuntu_sso/qt/tests/__init__.py (+1/-0)
ubuntu_sso/qt/tests/test_controllers.py (+318/-0)
ubuntu_sso/utils/tests/test_ui.py (+110/-0)
ubuntu_sso/utils/ui.py (+107/-0)
To merge this branch: bzr merge lp:~mandel/ubuntu-sso-client/windows_ui_3
Reviewer Review Type Date Requested Status
Alejandro J. Cura (community) fixes attached Approve
Roberto Alsina (community) Approve
Review via email: mp+55561@code.launchpad.net

This proposal supersedes a proposal from 2011-03-30.

Commit message

Provides the UI with the required controllers that will ensure that the navigation in the Wizard is the correct one. This branch does not yet provide the sso functionality.

Description of the change

Provides the UI with the required controllers that will ensure that the navigation in the Wizard is the correct one. This branch does not yet provide the sso functionality.

To post a comment you must log in.
Revision history for this message
Roberto Alsina (ralsina) wrote :

+1

review: Approve
Revision history for this message
Alejandro J. Cura (alecu) wrote :

Lovely branch!

A few fixes needed, but since they are not blocking, I'm approving anyway:

"Controlled to the ChooseSignIn view/widget." -> EPARSE
"Setting tranlated strings" -> +"s" times two
"Conroller for the setup account view" -> +"t"
"enxt" -> please unwrap
"strengh" -> +"t" times many
"Ui_ChooseSingInPage" -> "Sign"
"Represents and enhanced lineedit." -> "an"
"to the cation that will" -> "caption"?
"loginc" -> -"c"
"lwer" -> "lower"
"minimun" -> "minimum"

_strong, _medium, _weak_color -> move the QColors as constants
lines 1680, 1681 in the diff -> remove commented lines

review: Approve (fixes attached)
746. By Manuel de la Peña

Fixed mock test.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'data/qt/choose_sign_in.ui'
--- data/qt/choose_sign_in.ui 2011-03-14 15:14:24 +0000
+++ data/qt/choose_sign_in.ui 2011-04-05 13:47:53 +0000
@@ -1,7 +1,7 @@
1<?xml version="1.0" encoding="UTF-8"?>1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">2<ui version="4.0">
3 <class>ChooseSingInWidget</class>3 <class>ChooseSignInPage</class>
4 <widget class="QWidget" name="ChooseSingInWidget">4 <widget class="QWizardPage" name="ChooseSingInPage">
5 <property name="geometry">5 <property name="geometry">
6 <rect>6 <rect>
7 <x>0</x>7 <x>0</x>
@@ -11,7 +11,7 @@
11 </rect>11 </rect>
12 </property>12 </property>
13 <property name="windowTitle">13 <property name="windowTitle">
14 <string>Form</string>14 <string>WizardPage</string>
15 </property>15 </property>
16 <layout class="QHBoxLayout" name="horizontalLayout">16 <layout class="QHBoxLayout" name="horizontalLayout">
17 <item>17 <item>
@@ -50,9 +50,9 @@
50 <item>50 <item>
51 <layout class="QHBoxLayout" name="horizontalLayout_2">51 <layout class="QHBoxLayout" name="horizontalLayout_2">
52 <item>52 <item>
53 <widget class="QPushButton" name="_existingAccountButton">53 <widget class="QPushButton" name="existing_account_button">
54 <property name="text">54 <property name="text">
55 <string>Sign me in with my existing account</string>55 <string/>
56 </property>56 </property>
57 </widget>57 </widget>
58 </item>58 </item>
@@ -75,9 +75,9 @@
75 </spacer>75 </spacer>
76 </item>76 </item>
77 <item>77 <item>
78 <widget class="QPushButton" name="_setUpAccountButton">78 <widget class="QPushButton" name="setup_account_button">
79 <property name="text">79 <property name="text">
80 <string>I don't have an account yet - sign me up</string>80 <string/>
81 </property>81 </property>
82 </widget>82 </widget>
83 </item>83 </item>
8484
=== modified file 'data/qt/current_user_sign_in.ui'
--- data/qt/current_user_sign_in.ui 2011-03-14 12:18:54 +0000
+++ data/qt/current_user_sign_in.ui 2011-04-05 13:47:53 +0000
@@ -1,22 +1,19 @@
1<?xml version="1.0" encoding="UTF-8"?>1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">2<ui version="4.0">
3 <class>CurrentUserSignInWidget</class>3 <class>CurrentUserSignInPage</class>
4 <widget class="QWidget" name="CurrentUserSignInWidget">4 <widget class="QWizardPage" name="CurrentUserSignInPage">
5 <property name="geometry">5 <property name="geometry">
6 <rect>6 <rect>
7 <x>0</x>7 <x>0</x>
8 <y>0</y>8 <y>0</y>
9 <width>511</width>9 <width>400</width>
10 <height>373</height>10 <height>300</height>
11 </rect>11 </rect>
12 </property>12 </property>
13 <property name="windowTitle">13 <property name="windowTitle">
14 <string>Form</string>14 <string>WizardPage</string>
15 </property>15 </property>
16 <property name="locale">16 <layout class="QHBoxLayout" name="horizontalLayout">
17 <locale language="English" country="UnitedStates"/>
18 </property>
19 <layout class="QHBoxLayout" name="horizontalLayout_2">
20 <item>17 <item>
21 <layout class="QHBoxLayout" name="horizontalLayout_3">18 <layout class="QHBoxLayout" name="horizontalLayout_3">
22 <item>19 <item>
@@ -57,78 +54,34 @@
57 </property>54 </property>
58 <layout class="QVBoxLayout" name="verticalLayout_3">55 <layout class="QVBoxLayout" name="verticalLayout_3">
59 <item>56 <item>
60 <widget class="QLabel" name="_titleLabel">
61 <property name="sizePolicy">
62 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
63 <horstretch>0</horstretch>
64 <verstretch>0</verstretch>
65 </sizepolicy>
66 </property>
67 <property name="text">
68 <string>Sign in to Ubuntu One</string>
69 </property>
70 </widget>
71 </item>
72 <item>
73 <spacer name="verticalSpacer">
74 <property name="orientation">
75 <enum>Qt::Vertical</enum>
76 </property>
77 <property name="sizeType">
78 <enum>QSizePolicy::Fixed</enum>
79 </property>
80 <property name="sizeHint" stdset="0">
81 <size>
82 <width>20</width>
83 <height>10</height>
84 </size>
85 </property>
86 </spacer>
87 </item>
88 <item>
89 <layout class="QVBoxLayout" name="verticalLayout_2">57 <layout class="QVBoxLayout" name="verticalLayout_2">
90 <item>58 <item>
91 <widget class="QLabel" name="_emailLabel">59 <widget class="QLineEdit" name="email_edit">
92 <property name="sizePolicy">60 <property name="placeholderText">
93 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">61 <string/>
94 <horstretch>0</horstretch>62 </property>
95 <verstretch>0</verstretch>63 </widget>
96 </sizepolicy>64 </item>
97 </property>65 <item>
98 <property name="text">66 <widget class="QLineEdit" name="password_edit">
99 <string>Email</string>67 <property name="echoMode">
100 </property>68 <enum>QLineEdit::Password</enum>
101 </widget>69 </property>
102 </item>70 <property name="placeholderText">
103 <item>71 <string/>
104 <widget class="QLineEdit" name="_emailEdit"/>72 </property>
105 </item>73 </widget>
106 <item>74 </item>
107 <widget class="QLabel" name="_passwordLabel">75 <item>
108 <property name="sizePolicy">76 <widget class="QLabel" name="forgot_label">
109 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">77 <property name="sizePolicy">
110 <horstretch>0</horstretch>78 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
111 <verstretch>0</verstretch>79 <horstretch>0</horstretch>
112 </sizepolicy>80 <verstretch>0</verstretch>
113 </property>81 </sizepolicy>
114 <property name="text">82 </property>
115 <string>Password</string>83 <property name="text">
116 </property>84 <string/>
117 </widget>
118 </item>
119 <item>
120 <widget class="QLineEdit" name="_passwordEdit"/>
121 </item>
122 <item>
123 <widget class="QLabel" name="_forgotLabel">
124 <property name="sizePolicy">
125 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
126 <horstretch>0</horstretch>
127 <verstretch>0</verstretch>
128 </sizepolicy>
129 </property>
130 <property name="text">
131 <string>Forgot password?</string>
132 </property>85 </property>
133 </widget>86 </widget>
134 </item>87 </item>
@@ -148,9 +101,9 @@
148 </spacer>101 </spacer>
149 </item>102 </item>
150 <item>103 <item>
151 <widget class="QPushButton" name="_signInButton">104 <widget class="QPushButton" name="sign_in_button">
152 <property name="text">105 <property name="text">
153 <string>Sign in</string>106 <string/>
154 </property>107 </property>
155 </widget>108 </widget>
156 </item>109 </item>
157110
=== modified file 'data/qt/email_verification.ui'
--- data/qt/email_verification.ui 2011-03-14 12:18:54 +0000
+++ data/qt/email_verification.ui 2011-04-05 13:47:53 +0000
@@ -1,7 +1,7 @@
1<?xml version="1.0" encoding="UTF-8"?>1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">2<ui version="4.0">
3 <class>EmailVerificationWidget</class>3 <class>EmailVerificationPage</class>
4 <widget class="QWidget" name="EmailVerificationWidget">4 <widget class="QWizardPage" name="EmailVerificationPage">
5 <property name="geometry">5 <property name="geometry">
6 <rect>6 <rect>
7 <x>0</x>7 <x>0</x>
@@ -11,7 +11,7 @@
11 </rect>11 </rect>
12 </property>12 </property>
13 <property name="windowTitle">13 <property name="windowTitle">
14 <string>Form</string>14 <string>WizardPage</string>
15 </property>15 </property>
16 <layout class="QHBoxLayout" name="horizontalLayout">16 <layout class="QHBoxLayout" name="horizontalLayout">
17 <item>17 <item>
@@ -35,34 +35,9 @@
35 <item>35 <item>
36 <layout class="QVBoxLayout" name="verticalLayout">36 <layout class="QVBoxLayout" name="verticalLayout">
37 <item>37 <item>
38 <spacer name="verticalSpacer_3">38 <widget class="QLineEdit" name="verification_code_edit">
39 <property name="orientation">
40 <enum>Qt::Vertical</enum>
41 </property>
42 <property name="sizeHint" stdset="0">
43 <size>
44 <width>20</width>
45 <height>40</height>
46 </size>
47 </property>
48 </spacer>
49 </item>
50 <item>
51 <widget class="QLabel" name="_introLabel">
52 <property name="text">
53 <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
54&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
55p, li { white-space: pre-wrap; }
56&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
57&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;We have sent you an email with a special code in it.&lt;/span&gt;&lt;/p&gt;
58&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;Please check you email and enter the code here.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
59 </property>
60 </widget>
61 </item>
62 <item>
63 <widget class="QLineEdit" name="_verificationCodeEdit">
64 <property name="placeholderText">39 <property name="placeholderText">
65 <string>Enter email verification code</string>40 <string/>
66 </property>41 </property>
67 </widget>42 </widget>
68 </item>43 </item>
@@ -82,7 +57,7 @@
82 </spacer>57 </spacer>
83 </item>58 </item>
84 <item>59 <item>
85 <widget class="QPushButton" name="_nextButton">60 <widget class="QPushButton" name="next_button">
86 <property name="text">61 <property name="text">
87 <string>Next</string>62 <string>Next</string>
88 </property>63 </property>
8964
=== modified file 'data/qt/setup_account.ui'
--- data/qt/setup_account.ui 2011-03-14 12:18:54 +0000
+++ data/qt/setup_account.ui 2011-04-05 13:47:53 +0000
@@ -1,60 +1,259 @@
1<?xml version="1.0" encoding="UTF-8"?>1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">2<ui version="4.0">
3 <class>SetUpAccountWidget</class>3 <class>SetUpAccountPage</class>
4 <widget class="QWidget" name="SetUpAccountWidget">4 <widget class="QWizardPage" name="SetUpAccountPage">
5 <property name="geometry">5 <property name="geometry">
6 <rect>6 <rect>
7 <x>0</x>7 <x>0</x>
8 <y>0</y>8 <y>0</y>
9 <width>646</width>9 <width>415</width>
10 <height>473</height>10 <height>359</height>
11 </rect>11 </rect>
12 </property>12 </property>
13 <property name="windowTitle">13 <property name="windowTitle">
14 <string>Form</string>14 <string>WizardPage</string>
15 </property>15 </property>
16 <layout class="QHBoxLayout" name="horizontalLayout">16 <layout class="QHBoxLayout" name="horizontalLayout">
17 <item>17 <item>
18 <layout class="QHBoxLayout" name="horizontalLayout_3">18 <layout class="QVBoxLayout" name="verticalLayout">
19 <item>19 <item>
20 <spacer name="horizontalSpacer_2">20 <spacer name="verticalSpacer_3">
21 <property name="orientation">21 <property name="orientation">
22 <enum>Qt::Horizontal</enum>22 <enum>Qt::Vertical</enum>
23 </property>
24 <property name="sizeType">
25 <enum>QSizePolicy::Fixed</enum>
26 </property>23 </property>
27 <property name="sizeHint" stdset="0">24 <property name="sizeHint" stdset="0">
28 <size>25 <size>
29 <width>40</width>26 <width>20</width>
30 <height>20</height>27 <height>40</height>
31 </size>28 </size>
32 </property>29 </property>
33 </spacer>30 </spacer>
34 </item>31 </item>
35 <item>32 <item>
36 <layout class="QVBoxLayout" name="verticalLayout">33 <widget class="QFrame" name="_signInFrame">
37 <item>34 <property name="frameShape">
38 <spacer name="verticalSpacer_3">35 <enum>QFrame::NoFrame</enum>
39 <property name="orientation">36 </property>
40 <enum>Qt::Vertical</enum>37 <layout class="QVBoxLayout" name="verticalLayout_3">
41 </property>38 <item>
42 <property name="sizeHint" stdset="0">39 <layout class="QVBoxLayout" name="verticalLayout_2">
43 <size>40 <item>
44 <width>20</width>41 <layout class="QVBoxLayout" name="verticalLayout_7">
45 <height>40</height>42 <item>
46 </size>43 <layout class="QHBoxLayout" name="horizontalLayout_10">
47 </property>44 <item>
48 </spacer>45 <widget class="QLineEdit" name="first_name_edit">
49 </item>46 <property name="placeholderText">
50 <item>47 <string/>
51 <widget class="QFrame" name="_signInFrame">48 </property>
52 <property name="frameShape">49 </widget>
53 <enum>QFrame::NoFrame</enum>50 </item>
54 </property>51 <item>
55 <layout class="QVBoxLayout" name="verticalLayout_3">52 <widget class="QLineEdit" name="last_name_edit">
56 <item>53 <property name="placeholderText">
57 <widget class="QLabel" name="_titleLabel">54 <string/>
55 </property>
56 </widget>
57 </item>
58 </layout>
59 </item>
60 <item>
61 <layout class="QHBoxLayout" name="horizontalLayout_11">
62 <item>
63 <widget class="QLineEdit" name="email_edit">
64 <property name="placeholderText">
65 <string/>
66 </property>
67 </widget>
68 </item>
69 <item>
70 <widget class="QLineEdit" name="confirm_email_edit">
71 <property name="placeholderText">
72 <string/>
73 </property>
74 </widget>
75 </item>
76 </layout>
77 </item>
78 <item>
79 <layout class="QHBoxLayout" name="horizontalLayout_12">
80 <item>
81 <layout class="QVBoxLayout" name="verticalLayout_32">
82 <item>
83 <widget class="QLineEdit" name="password_edit">
84 <property name="toolTip">
85 <string>Your password must be at least 8 characters long and at least contain one number and one upper later.</string>
86 </property>
87 <property name="statusTip">
88 <string/>
89 </property>
90 <property name="echoMode">
91 <enum>QLineEdit::Password</enum>
92 </property>
93 <property name="placeholderText">
94 <string/>
95 </property>
96 </widget>
97 </item>
98 <item>
99 <widget class="QFrame" name="strenght_frame">
100 <property name="sizePolicy">
101 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
102 <horstretch>0</horstretch>
103 <verstretch>0</verstretch>
104 </sizepolicy>
105 </property>
106 <property name="minimumSize">
107 <size>
108 <width>0</width>
109 <height>20</height>
110 </size>
111 </property>
112 <property name="maximumSize">
113 <size>
114 <width>16777215</width>
115 <height>30</height>
116 </size>
117 </property>
118 <property name="locale">
119 <locale language="English" country="UnitedStates"/>
120 </property>
121 <property name="frameShape">
122 <enum>QFrame::StyledPanel</enum>
123 </property>
124 <property name="frameShadow">
125 <enum>QFrame::Raised</enum>
126 </property>
127 <layout class="QHBoxLayout" name="horizontalLayout_15">
128 <property name="spacing">
129 <number>3</number>
130 </property>
131 <property name="leftMargin">
132 <number>2</number>
133 </property>
134 <property name="topMargin">
135 <number>0</number>
136 </property>
137 <property name="rightMargin">
138 <number>2</number>
139 </property>
140 <property name="bottomMargin">
141 <number>2</number>
142 </property>
143 <item>
144 <widget class="QFrame" name="weak_frame">
145 <property name="maximumSize">
146 <size>
147 <width>16777215</width>
148 <height>10</height>
149 </size>
150 </property>
151 <property name="frameShape">
152 <enum>QFrame::StyledPanel</enum>
153 </property>
154 <property name="frameShadow">
155 <enum>QFrame::Plain</enum>
156 </property>
157 <layout class="QVBoxLayout" name="verticalLayout_33">
158 <property name="margin">
159 <number>0</number>
160 </property>
161 </layout>
162 </widget>
163 </item>
164 <item>
165 <widget class="QFrame" name="medium_frame">
166 <property name="maximumSize">
167 <size>
168 <width>16777215</width>
169 <height>10</height>
170 </size>
171 </property>
172 <property name="frameShape">
173 <enum>QFrame::StyledPanel</enum>
174 </property>
175 <property name="frameShadow">
176 <enum>QFrame::Plain</enum>
177 </property>
178 <layout class="QVBoxLayout" name="verticalLayout_34">
179 <property name="margin">
180 <number>0</number>
181 </property>
182 </layout>
183 </widget>
184 </item>
185 <item>
186 <widget class="QFrame" name="strong_frame">
187 <property name="maximumSize">
188 <size>
189 <width>16777215</width>
190 <height>10</height>
191 </size>
192 </property>
193 <property name="frameShape">
194 <enum>QFrame::StyledPanel</enum>
195 </property>
196 <property name="frameShadow">
197 <enum>QFrame::Plain</enum>
198 </property>
199 <layout class="QVBoxLayout" name="verticalLayout_35">
200 <property name="margin">
201 <number>0</number>
202 </property>
203 </layout>
204 </widget>
205 </item>
206 </layout>
207 </widget>
208 </item>
209 <item>
210 <spacer name="_strenghSpacer">
211 <property name="orientation">
212 <enum>Qt::Vertical</enum>
213 </property>
214 <property name="sizeHint" stdset="0">
215 <size>
216 <width>20</width>
217 <height>5</height>
218 </size>
219 </property>
220 </spacer>
221 </item>
222 </layout>
223 </item>
224 <item>
225 <layout class="QVBoxLayout" name="verticalLayout_8">
226 <item>
227 <widget class="QLineEdit" name="confirm_password_edit">
228 <property name="echoMode">
229 <enum>QLineEdit::Password</enum>
230 </property>
231 <property name="placeholderText">
232 <string/>
233 </property>
234 </widget>
235 </item>
236 <item>
237 <spacer name="verticalSpacer_6">
238 <property name="orientation">
239 <enum>Qt::Vertical</enum>
240 </property>
241 <property name="sizeHint" stdset="0">
242 <size>
243 <width>20</width>
244 <height>10</height>
245 </size>
246 </property>
247 </spacer>
248 </item>
249 </layout>
250 </item>
251 </layout>
252 </item>
253 </layout>
254 </item>
255 <item>
256 <widget class="QLabel" name="password_info_label">
58 <property name="sizePolicy">257 <property name="sizePolicy">
59 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">258 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
60 <horstretch>0</horstretch>259 <horstretch>0</horstretch>
@@ -62,21 +261,7 @@
62 </sizepolicy>261 </sizepolicy>
63 </property>262 </property>
64 <property name="text">263 <property name="text">
65 <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;264 <string/>
66&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
67p, li { white-space: pre-wrap; }
68&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
69&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:14pt;&quot;&gt;Create&lt;/span&gt;&lt;span style=&quot; font-size:14pt; font-weight:600;&quot;&gt; Ubuntu One&lt;/span&gt;&lt;span style=&quot; font-size:14pt;&quot;&gt; account&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
70 </property>
71 <property name="textFormat">
72 <enum>Qt::RichText</enum>
73 </property>
74 </widget>
75 </item>
76 <item>
77 <widget class="QLabel" name="_infoLabel">
78 <property name="text">
79 <string>Ubuntu One requires and Ubuntu Single Sign On (SSO) account. This process will allow you to create a new account, if you do not yet have one. </string>
80 </property>265 </property>
81 <property name="wordWrap">266 <property name="wordWrap">
82 <bool>true</bool>267 <bool>true</bool>
@@ -84,417 +269,137 @@
84 </widget>269 </widget>
85 </item>270 </item>
86 <item>271 <item>
87 <spacer name="verticalSpacer">272 <layout class="QVBoxLayout" name="verticalLayout_9">
88 <property name="orientation">273 <item>
89 <enum>Qt::Vertical</enum>274 <widget class="QFrame" name="frame_2">
90 </property>
91 <property name="sizeType">
92 <enum>QSizePolicy::Fixed</enum>
93 </property>
94 <property name="sizeHint" stdset="0">
95 <size>
96 <width>20</width>
97 <height>10</height>
98 </size>
99 </property>
100 </spacer>
101 </item>
102 <item>
103 <layout class="QVBoxLayout" name="verticalLayout_2">
104 <item>
105 <layout class="QVBoxLayout" name="verticalLayout_7">
106 <item>
107 <layout class="QHBoxLayout" name="horizontalLayout_10">
108 <item>
109 <widget class="QLineEdit" name="_firstNameEdit">
110 <property name="placeholderText">
111 <string>Name</string>
112 </property>
113 </widget>
114 </item>
115 <item>
116 <widget class="QLineEdit" name="_lastNameEdit">
117 <property name="placeholderText">
118 <string>Surname</string>
119 </property>
120 </widget>
121 </item>
122 </layout>
123 </item>
124 <item>
125 <layout class="QHBoxLayout" name="horizontalLayout_11">
126 <item>
127 <widget class="QLineEdit" name="_emailAddresslEdit">
128 <property name="placeholderText">
129 <string>Email address</string>
130 </property>
131 </widget>
132 </item>
133 <item>
134 <widget class="QLineEdit" name="_confirmEmailAddressEdit">
135 <property name="placeholderText">
136 <string>Re-type Email address</string>
137 </property>
138 </widget>
139 </item>
140 </layout>
141 </item>
142 <item>
143 <layout class="QHBoxLayout" name="horizontalLayout_12">
144 <item>
145 <layout class="QVBoxLayout" name="verticalLayout_32">
146 <item>
147 <widget class="QLineEdit" name="_passwordEdit">
148 <property name="toolTip">
149 <string>Your password must be at least 8 characters long and at least contain one number and one upper later.</string>
150 </property>
151 <property name="statusTip">
152 <string/>
153 </property>
154 <property name="echoMode">
155 <enum>QLineEdit::Password</enum>
156 </property>
157 <property name="placeholderText">
158 <string>Password</string>
159 </property>
160 </widget>
161 </item>
162 <item>
163 <widget class="QFrame" name="_strenghtFrame">
164 <property name="sizePolicy">
165 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
166 <horstretch>0</horstretch>
167 <verstretch>0</verstretch>
168 </sizepolicy>
169 </property>
170 <property name="minimumSize">
171 <size>
172 <width>0</width>
173 <height>20</height>
174 </size>
175 </property>
176 <property name="maximumSize">
177 <size>
178 <width>16777215</width>
179 <height>30</height>
180 </size>
181 </property>
182 <property name="locale">
183 <locale language="English" country="UnitedStates"/>
184 </property>
185 <property name="frameShape">
186 <enum>QFrame::StyledPanel</enum>
187 </property>
188 <property name="frameShadow">
189 <enum>QFrame::Raised</enum>
190 </property>
191 <layout class="QHBoxLayout" name="horizontalLayout_15">
192 <property name="spacing">
193 <number>3</number>
194 </property>
195 <property name="leftMargin">
196 <number>2</number>
197 </property>
198 <property name="topMargin">
199 <number>0</number>
200 </property>
201 <property name="rightMargin">
202 <number>2</number>
203 </property>
204 <property name="bottomMargin">
205 <number>2</number>
206 </property>
207 <item>
208 <widget class="QFrame" name="_weakFrame">
209 <property name="maximumSize">
210 <size>
211 <width>16777215</width>
212 <height>10</height>
213 </size>
214 </property>
215 <property name="frameShape">
216 <enum>QFrame::StyledPanel</enum>
217 </property>
218 <property name="frameShadow">
219 <enum>QFrame::Plain</enum>
220 </property>
221 <layout class="QVBoxLayout" name="verticalLayout_33">
222 <property name="margin">
223 <number>0</number>
224 </property>
225 </layout>
226 </widget>
227 </item>
228 <item>
229 <widget class="QFrame" name="_mediumFrame">
230 <property name="maximumSize">
231 <size>
232 <width>16777215</width>
233 <height>10</height>
234 </size>
235 </property>
236 <property name="frameShape">
237 <enum>QFrame::StyledPanel</enum>
238 </property>
239 <property name="frameShadow">
240 <enum>QFrame::Plain</enum>
241 </property>
242 <layout class="QVBoxLayout" name="verticalLayout_34">
243 <property name="margin">
244 <number>0</number>
245 </property>
246 </layout>
247 </widget>
248 </item>
249 <item>
250 <widget class="QFrame" name="_strongFrame">
251 <property name="maximumSize">
252 <size>
253 <width>16777215</width>
254 <height>10</height>
255 </size>
256 </property>
257 <property name="frameShape">
258 <enum>QFrame::StyledPanel</enum>
259 </property>
260 <property name="frameShadow">
261 <enum>QFrame::Plain</enum>
262 </property>
263 <layout class="QVBoxLayout" name="verticalLayout_35">
264 <property name="margin">
265 <number>0</number>
266 </property>
267 </layout>
268 </widget>
269 </item>
270 </layout>
271 </widget>
272 </item>
273 <item>
274 <spacer name="_strenghSpacer">
275 <property name="orientation">
276 <enum>Qt::Vertical</enum>
277 </property>
278 <property name="sizeHint" stdset="0">
279 <size>
280 <width>20</width>
281 <height>5</height>
282 </size>
283 </property>
284 </spacer>
285 </item>
286 </layout>
287 </item>
288 <item>
289 <layout class="QVBoxLayout" name="verticalLayout_8">
290 <item>
291 <widget class="QLineEdit" name="_confirmPasswordEdit">
292 <property name="echoMode">
293 <enum>QLineEdit::Password</enum>
294 </property>
295 <property name="placeholderText">
296 <string>Re-type password</string>
297 </property>
298 </widget>
299 </item>
300 <item>
301 <spacer name="verticalSpacer_6">
302 <property name="orientation">
303 <enum>Qt::Vertical</enum>
304 </property>
305 <property name="sizeHint" stdset="0">
306 <size>
307 <width>20</width>
308 <height>10</height>
309 </size>
310 </property>
311 </spacer>
312 </item>
313 </layout>
314 </item>
315 </layout>
316 </item>
317 </layout>
318 </item>
319 <item>
320 <widget class="QLabel" name="_passwordInfoLabel">
321 <property name="sizePolicy">275 <property name="sizePolicy">
322 <sizepolicy hsizetype="Preferred" vsizetype="Fixed">276 <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
323 <horstretch>0</horstretch>277 <horstretch>0</horstretch>
324 <verstretch>0</verstretch>278 <verstretch>0</verstretch>
325 </sizepolicy>279 </sizepolicy>
326 </property>280 </property>
327 <property name="text">281 <property name="frameShape">
328 <string>The password must have a minimum of 8 characters and include one uppercase character and one number.</string>282 <enum>QFrame::StyledPanel</enum>
329 </property>283 </property>
330 <property name="wordWrap">284 <property name="frameShadow">
331 <bool>true</bool>285 <enum>QFrame::Raised</enum>
332 </property>286 </property>
333 </widget>287 <layout class="QHBoxLayout" name="horizontalLayout_16">
334 </item>288 <property name="leftMargin">
335 <item>289 <number>0</number>
336 <layout class="QVBoxLayout" name="verticalLayout_9">290 </property>
337 <item>291 <item>
338 <widget class="QFrame" name="frame_2">292 <widget class="QLabel" name="captcha_view">
339 <property name="sizePolicy">293 <property name="frameShape">
340 <sizepolicy hsizetype="Minimum" vsizetype="Minimum">294 <enum>QFrame::Box</enum>
341 <horstretch>0</horstretch>295 </property>
342 <verstretch>0</verstretch>296 <property name="text">
343 </sizepolicy>297 <string/>
344 </property>298 </property>
345 <property name="frameShape">299 </widget>
346 <enum>QFrame::StyledPanel</enum>300 </item>
347 </property>301 <item>
348 <property name="frameShadow">302 <widget class="QLabel" name="refresh_label">
349 <enum>QFrame::Raised</enum>303 <property name="sizePolicy">
350 </property>304 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
351 <layout class="QHBoxLayout" name="horizontalLayout_16">305 <horstretch>0</horstretch>
352 <property name="leftMargin">306 <verstretch>0</verstretch>
353 <number>0</number>307 </sizepolicy>
354 </property>308 </property>
355 <item>309 <property name="locale">
356 <widget class="QGraphicsView" name="graphicsView">310 <locale language="English" country="UnitedStates"/>
357 <property name="sizePolicy">311 </property>
358 <sizepolicy hsizetype="Expanding" vsizetype="Fixed">312 <property name="text">
359 <horstretch>0</horstretch>313 <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
360 <verstretch>0</verstretch>
361 </sizepolicy>
362 </property>
363 <property name="maximumSize">
364 <size>
365 <width>16777215</width>
366 <height>70</height>
367 </size>
368 </property>
369 <property name="verticalScrollBarPolicy">
370 <enum>Qt::ScrollBarAlwaysOff</enum>
371 </property>
372 <property name="horizontalScrollBarPolicy">
373 <enum>Qt::ScrollBarAlwaysOff</enum>
374 </property>
375 <property name="interactive">
376 <bool>false</bool>
377 </property>
378 <property name="sceneRect">
379 <rectf>
380 <x>0.000000000000000</x>
381 <y>0.000000000000000</y>
382 <width>0.000000000000000</width>
383 <height>0.000000000000000</height>
384 </rectf>
385 </property>
386 </widget>
387 </item>
388 <item>
389 <widget class="QLabel" name="_refreshLabel">
390 <property name="sizePolicy">
391 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
392 <horstretch>0</horstretch>
393 <verstretch>0</verstretch>
394 </sizepolicy>
395 </property>
396 <property name="locale">
397 <locale language="English" country="UnitedStates"/>
398 </property>
399 <property name="text">
400 <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
401&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;314&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
402p, li { white-space: pre-wrap; }315p, li { white-space: pre-wrap; }
403&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;316&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
404&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;If you can't read this then &lt;/span&gt;&lt;a href=&quot;example.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;refresh&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; this page&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>317&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;If you can't read this then &lt;/span&gt;&lt;a href=&quot;example.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;refresh&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; this page&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
405 </property>318 </property>
406 <property name="wordWrap">319 <property name="wordWrap">
407 <bool>true</bool>320 <bool>true</bool>
408 </property>321 </property>
409 </widget>322 </widget>
410 </item>323 </item>
411 </layout>324 </layout>
412 </widget>325 </widget>
413 </item>326 </item>
414 <item>327 <item>
415 <widget class="QLineEdit" name="lineEdit">328 <widget class="QLineEdit" name="captcha_solution_edit">
416 <property name="locale">329 <property name="locale">
417 <locale language="English" country="UnitedStates"/>330 <locale language="English" country="UnitedStates"/>
418 </property>331 </property>
419 <property name="inputMask">332 <property name="inputMask">
420 <string/>333 <string/>
421 </property>334 </property>
422 <property name="text">335 <property name="text">
423 <string/>336 <string/>
424 </property>337 </property>
425 <property name="placeholderText">338 <property name="placeholderText">
426 <string>Type the characters above</string>339 <string/>
427 </property>340 </property>
428 </widget>341 </widget>
429 </item>342 </item>
430 </layout>343 </layout>
431 </item>344 </item>
432 <item>345 <item>
433 <widget class="QCheckBox" name="_termsCheckbox">346 <widget class="QCheckBox" name="terms_checkbox">
434 <property name="text">347 <property name="text">
435 <string>I agree with the Ubuntu One terms and conditions</string>348 <string/>
436 </property>349 </property>
437 </widget>350 </widget>
438 </item>351 </item>
439 <item>352 <item>
440 <layout class="QHBoxLayout" name="horizontalLayout_4">353 <layout class="QHBoxLayout" name="horizontalLayout_4">
441 <property name="spacing">354 <property name="spacing">
442 <number>0</number>355 <number>0</number>
443 </property>356 </property>
444 <item>357 <item>
445 <widget class="QPushButton" name="_termsButton">358 <widget class="QPushButton" name="terms_button">
446 <property name="text">359 <property name="text">
447 <string>Show Terms and Conditions</string>360 <string/>
448 </property>361 </property>
449 </widget>362 </widget>
450 </item>363 </item>
451 <item>364 <item>
452 <spacer name="horizontalSpacer_3">365 <spacer name="horizontalSpacer_3">
453 <property name="orientation">366 <property name="orientation">
454 <enum>Qt::Horizontal</enum>367 <enum>Qt::Horizontal</enum>
455 </property>368 </property>
456 <property name="sizeHint" stdset="0">369 <property name="sizeHint" stdset="0">
457 <size>370 <size>
458 <width>40</width>371 <width>40</width>
459 <height>20</height>372 <height>20</height>
460 </size>373 </size>
461 </property>374 </property>
462 </spacer>375 </spacer>
463 </item>376 </item>
464 </layout>377 <item>
378 <widget class="QPushButton" name="set_up_button">
379 <property name="enabled">
380 <bool>false</bool>
381 </property>
382 <property name="text">
383 <string/>
384 </property>
385 </widget>
465 </item>386 </item>
466 </layout>387 </layout>
467 </item>388 </item>
468 </layout>389 </layout>
469 </widget>390 </item>
470 </item>391 </layout>
471 <item>392 </widget>
472 <spacer name="verticalSpacer_2">
473 <property name="orientation">
474 <enum>Qt::Vertical</enum>
475 </property>
476 <property name="sizeHint" stdset="0">
477 <size>
478 <width>20</width>
479 <height>40</height>
480 </size>
481 </property>
482 </spacer>
483 </item>
484 </layout>
485 </item>393 </item>
486 <item>394 <item>
487 <spacer name="horizontalSpacer">395 <spacer name="verticalSpacer_2">
488 <property name="orientation">396 <property name="orientation">
489 <enum>Qt::Horizontal</enum>397 <enum>Qt::Vertical</enum>
490 </property>
491 <property name="sizeType">
492 <enum>QSizePolicy::Fixed</enum>
493 </property>398 </property>
494 <property name="sizeHint" stdset="0">399 <property name="sizeHint" stdset="0">
495 <size>400 <size>
496 <width>40</width>401 <width>20</width>
497 <height>20</height>402 <height>40</height>
498 </size>403 </size>
499 </property>404 </property>
500 </spacer>405 </spacer>
501406
=== modified file 'data/qt/terms_and_conditions.ui'
--- data/qt/terms_and_conditions.ui 2011-03-14 12:22:58 +0000
+++ data/qt/terms_and_conditions.ui 2011-04-05 13:47:53 +0000
@@ -1,7 +1,7 @@
1<?xml version="1.0" encoding="UTF-8"?>1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">2<ui version="4.0">
3 <class>TermsAndConditionsWidget</class>3 <class>TosPage</class>
4 <widget class="QWidget" name="TermsAndConditionsWidget">4 <widget class="QWizardPage" name="TosPage">
5 <property name="geometry">5 <property name="geometry">
6 <rect>6 <rect>
7 <x>0</x>7 <x>0</x>
@@ -11,7 +11,7 @@
11 </rect>11 </rect>
12 </property>12 </property>
13 <property name="windowTitle">13 <property name="windowTitle">
14 <string>Form</string>14 <string>WizardPage</string>
15 </property>15 </property>
16 <layout class="QHBoxLayout" name="horizontalLayout">16 <layout class="QHBoxLayout" name="horizontalLayout">
17 <item>17 <item>
@@ -51,36 +51,6 @@
51 </spacer>51 </spacer>
52 </item>52 </item>
53 <item>53 <item>
54 <widget class="QLabel" name="_titleLabel">
55 <property name="text">
56 <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
57&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
58p, li { white-space: pre-wrap; }
59&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
60&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:14pt;&quot;&gt;Term and Conditions&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
61 </property>
62 <property name="textFormat">
63 <enum>Qt::RichText</enum>
64 </property>
65 </widget>
66 </item>
67 <item>
68 <spacer name="verticalSpacer">
69 <property name="orientation">
70 <enum>Qt::Vertical</enum>
71 </property>
72 <property name="sizeType">
73 <enum>QSizePolicy::Fixed</enum>
74 </property>
75 <property name="sizeHint" stdset="0">
76 <size>
77 <width>20</width>
78 <height>10</height>
79 </size>
80 </property>
81 </spacer>
82 </item>
83 <item>
84 <widget class="QScrollArea" name="scrollArea">54 <widget class="QScrollArea" name="scrollArea">
85 <property name="widgetResizable">55 <property name="widgetResizable">
86 <bool>true</bool>56 <bool>true</bool>
@@ -91,12 +61,12 @@
91 <x>0</x>61 <x>0</x>
92 <y>0</y>62 <y>0</y>
93 <width>284</width>63 <width>284</width>
94 <height>139</height>64 <height>184</height>
95 </rect>65 </rect>
96 </property>66 </property>
97 <layout class="QHBoxLayout" name="horizontalLayout_2">67 <layout class="QHBoxLayout" name="horizontalLayout_2">
98 <item>68 <item>
99 <widget class="QWebView" name="_termsWebkit">69 <widget class="QWebView" name="terms_webkit">
100 <property name="url">70 <property name="url">
101 <url>71 <url>
102 <string>about:blank</string>72 <string>about:blank</string>
10373
=== added file 'ubuntu_sso/qt/controllers.py'
--- ubuntu_sso/qt/controllers.py 1970-01-01 00:00:00 +0000
+++ ubuntu_sso/qt/controllers.py 2011-04-05 13:47:53 +0000
@@ -0,0 +1,260 @@
1# -*- coding: utf-8 -*-
2# Author: Manuel de la Pena <manuel@canonical.com>
3#
4# Copyright 2011 Canonical Ltd.
5#
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.
9#
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.
14#
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."""
18
19from PyQt4.QtCore import QUrl
20
21from ubuntu_sso.logger import setup_logging
22from ubuntu_sso.utils.ui import (
23 CAPTCHA_SOLUTION_ENTRY,
24 EMAIL1_ENTRY,
25 EMAIL2_ENTRY,
26 EXISTING_ACCOUNT_CHOICE_BUTTON,
27 FORGOTTEN_PASSWORD_BUTTON,
28 JOIN_HEADER_LABEL,
29 NAME_ENTRY,
30 PASSWORD1_ENTRY,
31 PASSWORD2_ENTRY,
32 PASSWORD_HELP,
33 SET_UP_ACCOUNT_CHOICE_BUTTON,
34 SET_UP_ACCOUNT_BUTTON,
35 SIGN_IN_BUTTON,
36 SURNAME_ENTRY,
37 TC_BUTTON,
38 VERIFY_EMAIL_TITLE,
39 VERIFY_EMAIL_CONTENT,
40 YES_TO_TC,
41 get_password_strength,
42 is_min_required_password)
43
44
45logger = setup_logging('ubuntu_sso.controllers')
46
47
48class ChooseSignInController(object):
49 """Controlled to the ChooseSignIn view/widget."""
50
51 def __init__(self, title='', existing_account_id=1,
52 new_account_id=2):
53 """Create a new instance to manage the view."""
54 self._title = title
55 self._existing_account_id = existing_account_id
56 self._new_account_id = new_account_id
57
58 # use an ugly name just so have a simlar api as found in PyQt
59 #pylint: disable=C0103
60 def setupUi(self, view):
61 """Perform the required actions to set up the ui."""
62 view.setTitle(self._title)
63 self._set_up_translated_strings(view)
64 self._connect_buttons(view)
65 #pylint: enable=C0103
66
67 def _set_up_translated_strings(self, view):
68 """Set the correct strings for the UI."""
69 view.existing_account_button.setText(EXISTING_ACCOUNT_CHOICE_BUTTON)
70 view.new_account_button.setText(SET_UP_ACCOUNT_CHOICE_BUTTON)
71
72 def _connect_buttons(self, view):
73 """Connect the buttons to the actions to perform."""
74 view.existing_account_button.clicked.connect(
75 lambda: self._set_next_existing(view))
76 view.new_account_button.clicked.connect(
77 lambda: self._set_next_new(view))
78
79 def _set_next_existing(self, view):
80 """Set the next id and fire signal."""
81 view.next = self._existing_account_id
82 view.wizard().next()
83
84 def _set_next_new(self, view):
85 """Set the next id and fire signal."""
86 view.next = self._new_account_id
87 view.wizard().next()
88
89
90class CurrentUserController(object):
91 """Controller used in the view that is used to allow the signin."""
92
93 def __init__(self, title=''):
94 """Create a new instance."""
95 self._title = title
96
97 def _set_translated_strings(self, view):
98 """Set the translated strings."""
99 logger.debug('Setting tranlated strings.')
100 view.email_edit.setPlaceholderText(EMAIL1_ENTRY)
101 view.password_edit.setPlaceholderText(PASSWORD1_ENTRY)
102 view.forgot_password_label.setText(FORGOTTEN_PASSWORD_BUTTON)
103 view.sign_in_button.setText(SIGN_IN_BUTTON)
104
105 # use an ugly name just so have a simlar api as found in PyQt
106 #pylint: disable=C0103
107 def setupUi(self, view):
108 """Setup the view."""
109 view.setTitle(self._title)
110 self._set_translated_strings(view)
111 #pylint: enable=C0103
112
113
114class SetUpAccountController(object):
115 """Conroller for the setup account view."""
116
117 def __init__(self, tos_id=0, validation_id=1, app_name='',
118 help_message=''):
119 """Create a new instance."""
120 self._tos_id = tos_id
121 self._validation_id = validation_id
122 self._app_name = app_name
123 self._help_message = help_message
124
125 def _set_translated_strings(self, view):
126 """Set the different gettext translated strings."""
127 logger.debug('Setting tranlated strings.')
128 # set the translated string
129 view.name_edit.setPlaceholderText(NAME_ENTRY)
130 view.last_name_edit.setPlaceholderText(SURNAME_ENTRY)
131 view.email_edit.setPlaceholderText(EMAIL1_ENTRY)
132 view.confirm_email_edit.setPlaceholderText(EMAIL2_ENTRY)
133 view.password_edit.setPlaceholderText(PASSWORD1_ENTRY)
134 view.confirm_password_edit.setPlaceholderText(PASSWORD2_ENTRY)
135 view.password_info_label.setText(PASSWORD_HELP)
136 view.captcha_solution_edit.setPlaceholderText(CAPTCHA_SOLUTION_ENTRY)
137 view.terms_and_conditions_check_box.setText(YES_TO_TC)
138 view.terms_and_conditions_button.setText(TC_BUTTON)
139 view.set_up_button.setText(SET_UP_ACCOUNT_BUTTON)
140
141 def _set_line_edits_validations(self, view):
142 """Set the validations to be performed on the edits."""
143 view.set_line_edit_validation_rule(view.email_edit,
144 self.is_correct_email)
145 # set the validation rule for the email confirmation
146 view.set_line_edit_validation_rule(view.confirm_email_edit,
147 lambda x: self.is_correct_email_confirmation(x, view))
148 # connect the changed text of the password to trigger a changed text
149 # in the confirm so that the validation is redone
150 view.email_edit.textChanged.connect(
151 view.confirm_email_edit.textChanged.emit)
152 view.set_line_edit_validation_rule(view.password_edit,
153 is_min_required_password)
154 view.set_line_edit_validation_rule(view.confirm_password_edit,
155 lambda x: self.is_correct_password_confirmation(x, view))
156 # same as the above case, lets connect a signal to a signal
157 view.password_edit.textChanged.connect(
158 view.confirm_password_edit.textChanged.emit)
159
160 def _connect_ui_elements(self, view):
161 """Set the connection of signals."""
162 view.terms_and_conditions_button.clicked.connect(
163 lambda: self.set_next_tos(view))
164 view.set_up_button.clicked.connect(lambda: self.set_next_validation(
165 view))
166 view.password_edit.textChanged.connect(
167 lambda x: self.update_password_strength(x, view))
168 view.terms_and_conditions_check_box.stateChanged.connect(
169 view.set_up_button.setEnabled)
170
171 def _set_titles(self, view):
172 """Set the diff titles of the view."""
173 view.setTitle(JOIN_HEADER_LABEL % {'app_name': self._app_name})
174 view.setSubTitle(self._help_message)
175
176 def set_next_tos(self, view):
177 """Set the tos page as the next one."""
178 view.next = self._tos_id
179 view.wizard().next()
180
181 def set_next_validation(self, view):
182 """Set the validation as the next page."""
183 view.next = self._validation_id
184 view.wizard().next()
185
186 def update_password_strength(self, password, view):
187 """Callback used to update the password strenght UI code."""
188 # get the strengh and then according to it color the frames
189 strengh = get_password_strength(password)
190 logger.info('Password strengh is %s', strengh)
191 view.set_strenght_level(strengh, password)
192
193 def is_correct_email(self, email_address):
194 """Return if the email is correct."""
195 return '@' in email_address
196
197 def is_correct_email_confirmation(self, email_address, view):
198 """Return that the email is the same."""
199 return view.email_edit.text() == email_address
200
201 def is_correct_password_confirmation(self, password, view):
202 """Return that the passwords are correct."""
203 return view.password_edit.text() == password
204
205 #pylint: disable=C0103
206 def setupUi(self, view):
207 """Setup the view."""
208 self._set_titles(view)
209 self._set_translated_strings(view)
210 self._set_line_edits_validations(view)
211 self._connect_ui_elements(view)
212 #pylint: enable=C0103
213
214
215class TosController(object):
216 """Controller used for the tos page."""
217
218 def __init__(self, title='', subtitle='', tos_url='http://www.ubuntu.com'):
219 """Create a new instance."""
220 self._title = title
221 self._subtitle = subtitle
222 self._tos_url = tos_url
223
224 #pylint: disable=C0103
225 def setupUi(self, view):
226 """Set up the ui."""
227 view.setTitle(self._title)
228 view.setSubTitle(self._subtitle)
229 # load the tos page
230 view.webkit.load(QUrl(self._tos_url))
231 #pylint: enable=C0103
232
233
234class EmailVerificationController(object):
235 """Controller used for the verification page."""
236
237 def _set_translated_strings(self, view):
238 """Set the trnaslated strings."""
239 view.verification_code_edit.setPlaceholderText(VERIFY_EMAIL_TITLE)
240
241 def _connect_ui_elements(self, view):
242 """Set the connection of signals."""
243 view.next_button.clicked.connect(lambda: self.next_page(view))
244
245 def _set_titles(self, view):
246 """Set the different titles."""
247 view.setTitle(VERIFY_EMAIL_TITLE)
248 view.setSubTitle(VERIFY_EMAIL_CONTENT)
249
250 #pylint: disable=C0103
251 def setupUi(self, view):
252 """Setup the view."""
253 self._set_titles(view)
254 self._set_translated_strings(view)
255 self._connect_ui_elements(view)
256 #pylint: enable=C0103
257
258 def next_page(self, view):
259 """Call the next action."""
260 view.wizard().next()
0261
=== modified file 'ubuntu_sso/qt/gui.py'
--- ubuntu_sso/qt/gui.py 2011-03-12 01:22:22 +0000
+++ ubuntu_sso/qt/gui.py 2011-04-05 13:47:53 +0000
@@ -16,6 +16,444 @@
16# with this program. If not, see <http://www.gnu.org/licenses/>.16# with this program. If not, see <http://www.gnu.org/licenses/>.
17"""Qt implementation of the UI."""17"""Qt implementation of the UI."""
1818
19from PyQt4 import Qt
20from PyQt4.QtGui import (
21 QApplication,
22 QColor,
23 QCursor,
24 QHBoxLayout,
25 QPalette,
26 QPixmap,
27 QPushButton,
28 QStyle,
29 QWizard,
30 QWizardPage,
31 QGraphicsScene)
32
33from ubuntu_sso.logger import setup_logging
34# pylint: disable=F0401,E0611
35from ubuntu_sso.qt.choose_sign_in_ui import Ui_ChooseSignInPage
36from ubuntu_sso.qt.current_user_sign_in_ui import Ui_CurrentUserSignInPage
37from ubuntu_sso.qt.email_verification_ui import Ui_EmailVerificationPage
38from ubuntu_sso.qt.setup_account_ui import Ui_SetUpAccountPage
39from ubuntu_sso.qt.terms_and_conditions_ui import Ui_TosPage
40# pylint: enable=F0401,E0611
41from ubuntu_sso.qt.controllers import (
42 ChooseSignInController,
43 CurrentUserController,
44 EmailVerificationController,
45 SetUpAccountController,
46 TosController)
47
48
49logger = setup_logging('ubuntu_sso.gui')
50
51# colors used to define the password stenght
52WEAK_COLOR = QColor(220, 20, 60)
53MEDIUN_COLOR = QColor(255, 215, 0)
54STRONG_COLOR = QColor(50, 205, 50)
55
56
57class ChooseSignInPage(QWizardPage):
58 """Widget that allows the user to choose how to sign in."""
59
60 def __init__(self, ui, controller, parent=None):
61 """Create a new widget to be used."""
62 QWizardPage.__init__(self, parent)
63 self.ui = ui
64 self.controller = controller
65 ui.setupUi(self)
66 controller.setupUi(self)
67 self.next = -1
68
69 # pylint: disable=C0103
70 def nextId(self):
71 """Provide the next id."""
72 return self.next
73 # pylint: enable=C0103
74
75 # allow to access to the different useful children
76 @property
77 def existing_account_button(self):
78 """Return the button used to sign in using an existing account."""
79 return self.ui.existing_account_button
80
81 @property
82 def new_account_button(self):
83 """Return the button used to sign in with a new account."""
84 return self.ui.setup_account_button
85
86
87class CurrentUserSignInPage(QWizardPage):
88 """Widget that allows to get the data of user to sign in."""
89
90 def __init__(self, ui, controller, parent=None):
91 """Create a new widget to be used."""
92 QWizardPage.__init__(self, parent)
93 self.ui = ui
94 self.controller = controller
95 self.ui.setupUi(self)
96 self.controller.setupUi(self)
97
98 # allow to access to the different useful data
99 @property
100 def email(self):
101 """Return the email data in the edit field."""
102 return str(self.ui.email_edit.text())
103
104 @property
105 def email_edit(self):
106 """Return the email edit that is used in the view."""
107 return self.ui.email_edit
108
109 @property
110 def password(self):
111 """Return the password data in the edit field."""
112 return str(self.ui.password_edit.text())
113
114 @property
115 def password_edit(self):
116 """Return the password edit used in the view."""
117 return self.ui.password_edit
118
119 @property
120 def forgot_password_label(self):
121 """Return the forgot password label."""
122 return self.ui.forgot_label
123
124 @property
125 def sign_in_button(self):
126 """Return the sign in button."""
127 return self.ui.sign_in_button
128
129
130class EmailVerificationPage(QWizardPage):
131 """Widget used to input the email verification code."""
132
133 def __init__(self, ui, controller, parent=None):
134 """Create a new widget to be used."""
135 QWizardPage.__init__(self, parent)
136 self.ui = ui
137 self.ui.setupUi(self)
138 self.controller = controller
139 self.controller.setupUi(self)
140
141 @property
142 def verification_code(self):
143 """Return the content of the verification code edit."""
144 return str(self.ui.verification_code_edit)
145
146 @property
147 def verification_code_edit(self):
148 """Return the edit used for the verification code."""
149 return self.ui.verification_code_edit
150
151 @property
152 def next_button(self):
153 """Return the button that move to the next stage."""
154 return self.ui.next_button
155
156
157class TosPage(QWizardPage):
158 """Widget used to show the tos."""
159
160 def __init__(self, ui, controller, parent=None):
161 """Create a new instance."""
162 QWizardPage.__init__(self, parent)
163 self.ui = ui
164 self.ui.setupUi(self)
165 self.controller = controller
166 self.controller.setupUi(self)
167
168 # pylint: disable=C0103
169 def nextId(self):
170 """Return the next page id."""
171 return -1
172 # pylint: enable=C0103
173
174 @property
175 def webkit(self):
176 """Return the webkit widget used to load the terms."""
177 return self.ui.terms_webkit
178
179
180class EnhancedLineEdit(object):
181 """Represents an enhanced lineedit.
182
183 This class works on an already added lineedit to the widget so
184 that we are just adding extra items to it.
185 """
186
187 def __init__(self, line_edit, valid_cb=lambda x: False):
188 """Create an instance."""
189 self._line_edit = line_edit
190 layout = QHBoxLayout(self._line_edit)
191 layout.setMargin(0)
192 self._line_edit.setLayout(layout)
193 self.valid_cb = valid_cb
194 layout.addStretch()
195 self.clear_button = QPushButton(self._line_edit)
196 layout.addWidget(self.clear_button)
197 self.clear_button.setMinimumSize(16, 16)
198 self.clear_button.setVisible(False)
199 self.clear_button.setFlat(True)
200 self.clear_button.setCursor(QCursor(0))
201 self.clear_button.setIcon(QApplication.style().standardIcon(
202 QStyle.SP_MessageBoxWarning))
203 # connect the change of text to the caption that will check if the
204 # text is valid and if the icon should be shown.
205 self._line_edit.textChanged.connect(self.show_button)
206
207 def show_button(self, string):
208 """Decide if we show the button or not."""
209 if not self.valid_cb(string):
210 self.clear_button.setVisible(True)
211 else:
212 self.clear_button.setVisible(False)
213
214
215class SetupAccountPage(QWizardPage):
216 """Widget used to create a new account."""
217
218 def __init__(self, ui, controller, parent=None):
219 """Create a new widget to be used."""
220 QWizardPage.__init__(self, parent)
221 self._enhanced_edits = {}
222 self.ui = ui
223 self.ui.setupUi(self)
224 # palettes that will be used to set the colors of the password strenght
225 original_palette = self.ui.strenght_frame.palette()
226 self._original_color = original_palette.background().color()
227 self.controller = controller
228 self.controller.setupUi(self)
229 self.next = -1
230 # create the scene to be used to show the captcha
231 self.image = None
232 self.image_file = None
233 self.scene = QGraphicsScene(self.ui.captcha_view)
234
235 def set_strenght_level(self, level, password):
236 """Set the strenght level colors."""
237 if password != '':
238 if level <= 1:
239 # low password
240 self._set_frame_color(self.ui.weak_frame, WEAK_COLOR)
241 self._set_frame_color(self.ui.medium_frame,
242 self._original_color)
243 self._set_frame_color(self.ui.strong_frame,
244 self._original_color)
245 elif level <= 3:
246 # medium password
247 self._set_frame_color(self.ui.weak_frame, MEDIUM_COLOR)
248 self._set_frame_color(self.ui.medium_frame, MEDIUM_COLOR)
249 self._set_frame_color(self.ui.strong_frame,
250 self._original_color)
251 else:
252 # nice!
253 self._set_frame_color(self.ui.weak_frame, STRONG_COLOR)
254 self._set_frame_color(self.ui.medium_frame, STRONG_COLOR)
255 self._set_frame_color(self.ui.strong_frame, STRONG_COLOR)
256 else:
257 # set it to the minimum
258 self._set_frame_color(self.ui.weak_frame, self._original_color)
259 self._set_frame_color(self.ui.medium_frame, self._original_color)
260 self._set_frame_color(self.ui.strong_frame, self._original_color)
261
262 def _set_frame_color(self, frame, color):
263 """Set the color of a frame to indicated a strenght."""
264 # change the color background for the given frame
265 palette = frame.palette()
266 palette.setColor(QPalette.Background, color)
267 frame.setPalette(palette)
268 frame.setAutoFillBackground(True)
269
270 # pylint: disable=C0103
271 def nextId(self):
272 """Return the next page id."""
273 return self.next
274 # pylint: enable=C0103
275
276 def set_line_edit_validation_rule(self, edit, cb):
277 """Set a new enhanced edit so that we can show an icon."""
278 if edit in self._enhanced_edits:
279 self._enhanced_edits[edit].valid_cb = cb
280 else:
281 # create a new enhanced edit
282 enhanced_edit = EnhancedLineEdit(edit, cb)
283 self._enhanced_edits[edit] = enhanced_edit
284
285 @property
286 def name(self):
287 """Return the name input."""
288 return str(self.ui.first_name_edit.text())
289
290 @property
291 def name_edit(self):
292 """Return the edit used for the name."""
293 return self.ui.first_name_edit
294
295 @property
296 def last_name(self):
297 """Return the last name input."""
298 return str(self.ui.last_name_edit.text())
299
300 @property
301 def last_name_edit(self):
302 """Return the edit used for the last name."""
303 return self.ui.last_name_edit
304
305 @property
306 def email(self):
307 """Return the email input."""
308 return str(self.ui.email_edit.text())
309
310 @property
311 def email_edit(self):
312 """Return the edit used for the email."""
313 return self.ui.email_edit
314
315 @property
316 def retyped_email(self):
317 """Return the retyped email."""
318 return str(self.ui.confirm_email_edit.text())
319
320 @property
321 def confirm_email_edit(self):
322 """Return the edit used for the retype of the email."""
323 return self.ui.confirm_email_edit
324
325 @property
326 def password_info_label(self):
327 """Return the password used to show the info of the label."""
328 return self.ui.password_info_label
329
330 @property
331 def password(self):
332 """Return the password data."""
333 return str(self.ui.password_edit.text())
334
335 @property
336 def password_edit(self):
337 """Return the edit used for the password."""
338 return self.ui.password_edit
339
340 @property
341 def retyped_password(self):
342 """Return the retyped password."""
343 return str(self.ui.confirm_password_edit.text())
344
345 @property
346 def confirm_password_edit(self):
347 """Return the edit used to confirm the password."""
348 return self.ui.confirm_password_edit
349
350 @property
351 def captcha_solution(self):
352 """Return the provided captcha solution."""
353 return str(self.ui.captcha_solution_edit.text())
354
355 @property
356 def captcha_solution_edit(self):
357 """Return the edit used for the captcha solution."""
358 return self.ui.captcha_solution_edit
359
360 def get_captcha_image(self):
361 """Return the path to the captcha image."""
362 return self.image_file
363
364 def set_captcha_image(self, file_path):
365 """Set the new image of the captcha."""
366 if self.image:
367 self.scene.removeItem(self.image)
368 self.image_file = file_path
369 pix = QPixmap(self.image_file)
370 self.image = self.scene.addPixmap(pix)
371
372 captcha_image = property(get_captcha_image, set_captcha_image)
373
374 @property
375 def terms_and_conditions_agreed(self):
376 """Return if the user agreed the terms."""
377 return self.ui.terms_checkbox.isChecked()
378
379 @property
380 def terms_and_conditions_check_box(self):
381 """Return the terms and codition item."""
382 return self.ui.terms_checkbox
383
384 @property
385 def terms_and_conditions_button(self):
386 """Return the terms and conditions button."""
387 return self.ui.terms_button
388
389 @property
390 def set_up_button(self):
391 """Return the set up button."""
392 return self.ui.set_up_button
393
394
395class UbuntuSSOWizard(QWizard):
396 """Wizard used to create or use sso."""
397
398 def __init__(self, parent=None, app_name='', tos_url='', help_text=''):
399 """Create a new wizard."""
400 QWizard.__init__(self, parent)
401 # set the diff pages of the QWizard
402 self.sign_in_controller = ChooseSignInController(title='Sign In',
403 existing_account_id=4,
404 new_account_id=1)
405 self.sign_in_page = ChooseSignInPage(Ui_ChooseSignInPage(),
406 self.sign_in_controller,
407 parent=self)
408 self.setup_controller = SetUpAccountController(tos_id=2,
409 validation_id=3,
410 app_name=app_name,
411 help_message='')
412 self.setup_account = SetupAccountPage(Ui_SetUpAccountPage(),
413 self.setup_controller,
414 parent=self)
415 self.tos = TosPage(Ui_TosPage(), TosController())
416 self.email_verification = EmailVerificationPage(
417 Ui_EmailVerificationPage(),
418 EmailVerificationController())
419 self.current_user_controller = CurrentUserController(title='Sign in')
420 self.current_user = CurrentUserSignInPage(Ui_CurrentUserSignInPage(),
421 self.current_user_controller,
422 parent=self)
423 for page in [self.sign_in_page, self.setup_account, self.tos,
424 self.email_verification, self.current_user]:
425 self.addPage(page)
426 # set the buttons layout to only have cancel and back since the next
427 # buttons are the ones used in the diff pages.
428 buttons_layout = []
429 buttons_layout.append(QWizard.Stretch)
430 buttons_layout.append(QWizard.BackButton)
431 buttons_layout.append(QWizard.CancelButton)
432 self.setButtonLayout(buttons_layout)
433 self.setWindowTitle(app_name)
434
435
436class UbuntuSSOWizardController(object):
437 """Performs the logic of the sso wizard."""
438
439 def __init__(self, app_name, tc_url='', help_text='',
440 window_id=0, login_only=False):
441 """Create a new instance."""
442 # create a new wizard and show it
443 self.wizard = None
444
19445
20class UbuntuSSOClientGUI(object):446class UbuntuSSOClientGUI(object):
21 """Ubuntu single sign-on GUI."""447 """Ubuntu single sign-on GUI."""
448
449if __name__ == '__main__':
450 # pylint: disable=C0103
451 # show the ui
452 import sys
453
454 app = Qt.QApplication(sys.argv)
455
456 wizard = UbuntuSSOWizard()
457 wizard.show()
458 # Now we can start it.
459 app.exec_()
22460
=== added directory 'ubuntu_sso/qt/tests'
=== added file 'ubuntu_sso/qt/tests/__init__.py'
--- ubuntu_sso/qt/tests/__init__.py 1970-01-01 00:00:00 +0000
+++ ubuntu_sso/qt/tests/__init__.py 2011-04-05 13:47:53 +0000
@@ -0,0 +1,1 @@
1"""Test the Ui code."""
02
=== added file 'ubuntu_sso/qt/tests/test_controllers.py'
--- ubuntu_sso/qt/tests/test_controllers.py 1970-01-01 00:00:00 +0000
+++ ubuntu_sso/qt/tests/test_controllers.py 2011-04-05 13:47:53 +0000
@@ -0,0 +1,318 @@
1# -*- coding: utf-8 -*-
2# Author: Manuel de la Pena <manuel@canonical.com>
3#
4# Copyright 2011 Canonical Ltd.
5#
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.
9#
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.
14#
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"""Test the ui controllers."""
18
19from mocker import ANY, MATCH, MockerTestCase
20
21from ubuntu_sso.qt.controllers import (
22 ChooseSignInController,
23 CurrentUserController,
24 EmailVerificationController,
25 SetUpAccountController,
26 TosController)
27from ubuntu_sso.utils.ui import (
28 CAPTCHA_SOLUTION_ENTRY,
29 EMAIL1_ENTRY,
30 EMAIL2_ENTRY,
31 EXISTING_ACCOUNT_CHOICE_BUTTON,
32 FORGOTTEN_PASSWORD_BUTTON,
33 JOIN_HEADER_LABEL,
34 NAME_ENTRY,
35 PASSWORD1_ENTRY,
36 PASSWORD2_ENTRY,
37 PASSWORD_HELP,
38 SET_UP_ACCOUNT_CHOICE_BUTTON,
39 SET_UP_ACCOUNT_BUTTON,
40 SIGN_IN_BUTTON,
41 SURNAME_ENTRY,
42 TC_BUTTON,
43 VERIFY_EMAIL_TITLE,
44 VERIFY_EMAIL_CONTENT,
45 YES_TO_TC,
46 is_min_required_password)
47
48#ignore the comon mocker issues with lint
49# pylint: disable=W0212,W0104
50
51
52class ChooseSignInControllerTestCase(MockerTestCase):
53 """Test the choose sign in controller."""
54
55 def setUp(self):
56 """Set tests."""
57 super(ChooseSignInControllerTestCase, self).setUp()
58 self.view = self.mocker.mock()
59 self.controller = ChooseSignInController()
60
61 def test_set_up_translated_strings(self):
62 """Ensure that the translations are used."""
63 self.view.existing_account_button.setText(
64 EXISTING_ACCOUNT_CHOICE_BUTTON)
65 self.view.new_account_button.setText(SET_UP_ACCOUNT_CHOICE_BUTTON)
66 self.mocker.replay()
67 self.controller._set_up_translated_strings(self.view)
68
69 def test_connect_buttons(self):
70 """Ensure that all the buttons are correcly connected."""
71 self.view.existing_account_button.clicked.connect(MATCH(callable))
72 self.view.new_account_button.clicked.connect(MATCH(callable))
73 self.mocker.replay()
74 self.controller._connect_buttons(self.view)
75
76 def test_set_next_existing(self):
77 """Test the execution of the callback."""
78 self.view.next = self.controller._existing_account_id
79 self.view.wizard().next()
80 self.mocker.replay()
81 self.controller._set_next_existing(self.view)
82
83 def test_set_next_new(self):
84 """Test the execution of the callback."""
85 self.view.next = self.controller._new_account_id
86 self.view.wizard().next()
87 self.mocker.replay()
88 self.controller._set_next_new(self.view)
89
90
91class CurrentUserControllerTestCase(MockerTestCase):
92 """Test the current user controller."""
93
94 def setUp(self):
95 """Setup tests."""
96 super(CurrentUserControllerTestCase, self).setUp()
97 self.view = self.mocker.mock()
98 self.controller = CurrentUserController(title='the title')
99
100 def test_setup_ui(self):
101 """test that the ui is correctly set up."""
102 self.view.setTitle(self.controller._title)
103 self.view.email_edit.setPlaceholderText(EMAIL1_ENTRY)
104 self.view.password_edit.setPlaceholderText(PASSWORD1_ENTRY)
105 self.view.forgot_password_label.setText(FORGOTTEN_PASSWORD_BUTTON)
106 self.view.sign_in_button.setText(SIGN_IN_BUTTON)
107 self.mocker.replay()
108 self.controller.setupUi(self.view)
109
110
111class SetUpAccountControllerTestCase(MockerTestCase):
112 """test the controller used to setup a new account."""
113
114 def setUp(self):
115 """Set the different tests."""
116 super(SetUpAccountControllerTestCase, self).setUp()
117 self.view = self.mocker.mock()
118 self.get_password_strength = self.mocker.replace(
119 'ubuntu_sso.utils.ui.get_password_strength')
120 self.app_name = 'test'
121 self.help = 'help'
122 self.controller = SetUpAccountController(app_name=self.app_name,
123 help_message=self.help)
124
125 def test_set_translated_strings(self):
126 """Ensure all the strings are set."""
127 self.view.name_edit.setPlaceholderText(NAME_ENTRY)
128 self.view.last_name_edit.setPlaceholderText(SURNAME_ENTRY)
129 self.view.email_edit.setPlaceholderText(EMAIL1_ENTRY)
130 self.view.confirm_email_edit.setPlaceholderText(EMAIL2_ENTRY)
131 self.view.password_edit.setPlaceholderText(PASSWORD1_ENTRY)
132 self.view.confirm_password_edit.setPlaceholderText(PASSWORD2_ENTRY)
133 self.view.password_info_label.setText(PASSWORD_HELP)
134 self.view.captcha_solution_edit.setPlaceholderText(
135 CAPTCHA_SOLUTION_ENTRY)
136 self.view.terms_and_conditions_check_box.setText(YES_TO_TC)
137 self.view.terms_and_conditions_button.setText(TC_BUTTON)
138 self.view.set_up_button.setText(SET_UP_ACCOUNT_BUTTON)
139 self.mocker.replay()
140 self.controller._set_translated_strings(self.view)
141
142 def test_set_titles(self):
143 """Test how the different titles are set."""
144 self.view.setTitle(JOIN_HEADER_LABEL % {'app_name': self.app_name})
145 self.view.setSubTitle(self.help)
146 self.mocker.replay()
147 self.controller._set_titles(self.view)
148
149 def test_connect_ui_elements(self):
150 """Test that the ui elements are correctly connect."""
151 self.view.terms_and_conditions_button.clicked.connect(MATCH(callable))
152 self.view.set_up_button.clicked.connect(MATCH(callable))
153 self.view.password_edit.textChanged.connect(MATCH(callable))
154 self.view.set_up_button.setEnabled
155 self.mocker.result(lambda:None)
156 self.view.terms_and_conditions_check_box.stateChanged.connect(
157 MATCH(callable))
158 self.mocker.replay()
159 self.controller._connect_ui_elements(self.view)
160
161 def test_is_correct_password_confirmation_false(self):
162 """Test when the password is not correct."""
163 password = 'test'
164 self.view.password_edit.text()
165 self.mocker.result('other')
166 self.mocker.replay()
167 self.assertFalse(
168 self.controller.is_correct_password_confirmation(password,
169 self.view))
170
171 def test_is_correct_password_confirmation_true(self):
172 """Test when the password is correct."""
173 password = 'test'
174 self.view.password_edit.text()
175 self.mocker.result(password)
176 self.mocker.replay()
177 self.assertTrue(
178 self.controller.is_correct_password_confirmation(password,
179 self.view))
180
181 def test_is_correct_email_confirmation_false(self):
182 """Test when the emails are not the same."""
183 email_address = 'address'
184 self.view.email_edit.text()
185 self.mocker.result('other')
186 self.mocker.replay()
187 self.assertFalse(
188 self.controller.is_correct_email_confirmation(email_address,
189 self.view))
190
191 def test_is_correct_email_confirmation_true(self):
192 """Test when the emails are the same."""
193 email_address = 'address'
194 self.view.email_edit.text()
195 self.mocker.result(email_address)
196 self.mocker.replay()
197 self.assertTrue(
198 self.controller.is_correct_email_confirmation(email_address,
199 self.view))
200
201 def test_is_correct_email_true(self):
202 """Test when the email is correct."""
203 email = 'manuel@canonical.com'
204 self.mocker.replay()
205 self.assertTrue(self.controller.is_correct_email(email))
206
207 def test_is_correct_email_false(self):
208 """Test when the email is not correct."""
209 email = 'manuelcanonical.com'
210 self.mocker.replay()
211 self.assertFalse(self.controller.is_correct_email(email))
212
213 def test_set_next_tos(self):
214 """Test the callback."""
215 self.view.next = self.controller._tos_id
216 self.view.wizard().next()
217 self.mocker.replay()
218 self.controller.set_next_tos(self.view)
219
220 def test_set_next_validation(self):
221 """Test the callback."""
222 self.view.next = self.controller._validation_id
223 self.view.wizard().next()
224 self.mocker.replay()
225 self.controller.set_next_validation(self.view)
226
227 def test_update_password_strength(self):
228 """Test the callback."""
229 password = 'test'
230 strength = 4
231 self.get_password_strength(password)
232 self.mocker.result(strength)
233 self.view.set_strenght_level(strength, password)
234 self.mocker.replay()
235 self.controller.update_password_strength(password, self.view)
236
237 def test_set_line_edits_validations(self):
238 """Set the validations to be performed on the edits."""
239 self.view.email_edit
240 self.mocker.result(self.view)
241 self.view.set_line_edit_validation_rule(self.view,
242 self.controller.is_correct_email)
243 self.view.confirm_email_edit
244 self.mocker.result(self.view)
245 self.view.set_line_edit_validation_rule(self.view, MATCH(callable))
246 self.view.confirm_email_edit.textChanged.emit
247 self.mocker.result(lambda: None)
248 self.view.email_edit.textChanged.connect(MATCH(callable))
249 self.view.password_edit
250 self.mocker.result(self.view)
251 self.view.set_line_edit_validation_rule(self.view,
252 is_min_required_password)
253 self.view.confirm_password_edit
254 self.mocker.result(self.view)
255 self.view.set_line_edit_validation_rule(self.view, MATCH(callable))
256 self.view.confirm_password_edit.textChanged.emit
257 self.mocker.result(lambda: None)
258 self.view.password_edit.textChanged.connect(MATCH(callable))
259 self.mocker.replay()
260 self.controller._set_line_edits_validations(self.view)
261
262
263class TosControllerTestCase(MockerTestCase):
264 """Test the tos controller."""
265
266 def setUp(self):
267 """Set the tests."""
268 super(TosControllerTestCase, self).setUp()
269 self.view = self.mocker.mock()
270 self.title = 'title'
271 self.subtitle = 'sub'
272 self.url = 'url'
273 self.controller = TosController(title=self.title,
274 subtitle=self.subtitle,
275 tos_url=self.url)
276
277 def test_setup_ui(self):
278 """Test the set up of the ui."""
279 self.view.setTitle(self.title)
280 self.view.setSubTitle(self.subtitle)
281 self.view.webkit.load(ANY)
282 self.mocker.replay()
283 self.controller.setupUi(self.view)
284
285
286class EmailVerificationControllerTestCase(MockerTestCase):
287 """Test the controller."""
288
289 def setUp(self):
290 """Set tests."""
291 super(EmailVerificationControllerTestCase, self).setUp()
292 self.view = self.mocker.mock()
293 self.controller = EmailVerificationController()
294
295 def test_set_translated_strings(self):
296 """Test that strings are translated."""
297 self.view.verification_code_edit.setPlaceholderText(VERIFY_EMAIL_TITLE)
298 self.mocker.replay()
299 self.controller._set_translated_strings(self.view)
300
301 def test_connect_ui_elements(self):
302 """Set the ui connections."""
303 self.view.next_button.clicked.connect(MATCH(callable))
304 self.mocker.replay()
305 self.controller._connect_ui_elements(self.view)
306
307 def test_set_titles(self):
308 """Test that the titles are set."""
309 self.view.setTitle(VERIFY_EMAIL_TITLE)
310 self.view.setSubTitle(VERIFY_EMAIL_CONTENT)
311 self.mocker.replay()
312 self.controller._set_titles(self.view)
313
314 def test_next_page(self):
315 """Test the callback."""
316 self.view.wizard().next()
317 self.mocker.replay()
318 self.controller.next_page(self.view)
0319
=== added file 'ubuntu_sso/utils/tests/test_ui.py'
--- ubuntu_sso/utils/tests/test_ui.py 1970-01-01 00:00:00 +0000
+++ ubuntu_sso/utils/tests/test_ui.py 2011-04-05 13:47:53 +0000
@@ -0,0 +1,110 @@
1# -*- coding: utf-8 -*-
2# Author: Manuel de la Pena <manuel@canonical.com>
3#
4# Copyright 2011 Canonical Ltd.
5#
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.
9#
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.
14#
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"""Test the ui functions."""
18
19from unittest import TestCase
20
21from ubuntu_sso.utils.ui import (get_password_strength,
22 is_min_required_password)
23
24
25class GetPasswordStrengTestCase(TestCase):
26 """Test the function that returns the strengh of a password."""
27
28 def test_too_small_password(self):
29 """Test the points given to a very small password."""
30 password = 'abc'
31 self.assertEqual(1, get_password_strength(password))
32
33 def test_small_password(self):
34 """Test the points given to a small passwod 4 or more chars."""
35 password = 'testtwe'
36 self.assertEqual(0, get_password_strength(password))
37
38 def test_eight_chars_password(self):
39 """Test the points given to a normal 8 chars password."""
40 password = 'abcdabcd'
41 self.assertEqual(1, get_password_strength(password))
42
43 def test_eight_chars_and_num(self):
44 """Test the points given to a 8 chars password with a num."""
45 password = 'abcdabc8'
46 self.assertEqual(2, get_password_strength(password))
47
48 def test_eight_chars_low_and_cap(self):
49 """Test the points given to a 8 chars password with a capital."""
50 password = 'abcdabcD'
51 self.assertEqual(2, get_password_strength(password))
52
53 def test_eight_chars_low_canp_num(self):
54 """Test the points given to a 8 chars password with capitals & num."""
55 password = 'abcdab7D'
56 self.assertEqual(3, get_password_strength(password))
57
58 def test_eiqgh_chars_and_special(self):
59 """Test the points given to a 8 chars password with special chars."""
60 password = 'abcdabc*'
61 self.assertEqual(2, get_password_strength(password))
62
63 def test_long_password(self):
64 """Test the points goven to a long password."""
65 password = 'abcdabcdabcd'
66 self.assertEqual(2, get_password_strength(password))
67
68 def test_eleven_chars_and_num(self):
69 """Test the points of a loong password with a num."""
70 password = 'abcdabcdabcd99'
71 self.assertEqual(3, get_password_strength(password))
72
73 def test_eleven_chars_low_cap(self):
74 """Test the points of a long password with low and cap."""
75 password = 'abcdabcdabcdbABCD'
76 self.assertEqual(3, get_password_strength(password))
77
78 def test_eleven_num_low_cap(self):
79 """Test the points of a long password with num and diff cap."""
80 password = 'ABCDabcdacbd723'
81 self.assertEqual(4, get_password_strength(password))
82
83 def test_eleven_num_special(self):
84 """Test the point of a long password with a number and special char."""
85 password = 'abcdabcdabcd*9'
86 self.assertEqual(4, get_password_strength(password))
87
88
89class IsMinRequiredPasswordTestCase(TestCase):
90 """Test the fnction that returns if the password is the min required."""
91
92 def test_no_enough_chars(self):
93 """Test a password that does not have enough chars."""
94 password = 'Test8'
95 self.assertFalse(is_min_required_password(password))
96
97 def test_no_uppercase(self):
98 """Test a password that does not have an uppercase."""
99 password = 'longenoughtobeapassword8'
100 self.assertFalse(is_min_required_password(password))
101
102 def test_no_number(self):
103 """Test a password that does not have a number."""
104 password = 'longenoughtobeapassworD'
105 self.assertFalse(is_min_required_password(password))
106
107 def test_correct_password(self):
108 """Test a password that is correct."""
109 password = 'TodasLasPaswordPasan88'
110 self.assertTrue(is_min_required_password(password))
0111
=== modified file 'ubuntu_sso/utils/ui.py'
--- ubuntu_sso/utils/ui.py 2011-03-25 09:54:38 +0000
+++ ubuntu_sso/utils/ui.py 2011-04-05 13:47:53 +0000
@@ -19,6 +19,7 @@
19"""Utils to be used by the UI modules."""19"""Utils to be used by the UI modules."""
2020
21import os21import os
22import re
22import xdg23import xdg
23import gettext24import gettext
2425
@@ -30,6 +31,69 @@
30gettext.textdomain('ubuntu-sso-client')31gettext.textdomain('ubuntu-sso-client')
31_ = gettext.gettext32_ = gettext.gettext
3233
34# all the text that is used in the gui
35CAPTCHA_SOLUTION_ENTRY = _('Type the characters above')
36CAPTCHA_LOAD_ERROR = _('There was a problem getting the captcha, '
37 'reloading...')
38CONNECT_HELP_LABEL = _('To connect this computer to %(app_name)s ' \
39 'enter your details below.')
40EMAIL1_ENTRY = _('Email address')
41EMAIL2_ENTRY = _('Re-type Email address')
42EMAIL_MISMATCH = _('The email addresses don\'t match, please double check '
43 'and try entering them again.')
44EMAIL_INVALID = _('The email must be a valid email address.')
45EMAIL_TOKEN_ENTRY = _('Enter code verification here')
46ERROR = _('The process did not finish successfully.')
47EXISTING_ACCOUNT_CHOICE_BUTTON = _('Sign me in with my existing account')
48FIELD_REQUIRED = _('This field is required.')
49FORGOTTEN_PASSWORD_BUTTON = _('I\'ve forgotten my password')
50JOIN_HEADER_LABEL = _('Create %(app_name)s account')
51LOADING = _('Loading...')
52LOGIN_BUTTON_LABEL = _('Already have an account? Click here to sign in')
53LOGIN_EMAIL_ENTRY = _('Email address')
54LOGIN_HEADER_LABEL = _('Connect to %(app_name)s')
55LOGIN_PASSWORD_ENTRY = _('Password')
56NAME_ENTRY = _('Name')
57NEXT = _('Next')
58ONE_MOMENT_PLEASE = _('One moment please...')
59PASSWORD_CHANGED = _('Your password was successfully changed.')
60PASSWORD1_ENTRY = RESET_PASSWORD1_ENTRY = _('Password')
61PASSWORD2_ENTRY = RESET_PASSWORD2_ENTRY = _('Re-type Password')
62PASSWORD_HELP = _('The password must have a minimum of 8 characters and ' \
63 'include one uppercase character and one number.')
64PASSWORD_MISMATCH = _('The passwords don\'t match, please double check ' \
65 'and try entering them again.')
66PASSWORD_TOO_WEAK = _('The password is too weak.')
67REQUEST_PASSWORD_TOKEN_LABEL = _('To reset your %(app_name)s password,'
68 ' enter your email address below:')
69RESET_PASSWORD = _('Reset password')
70RESET_CODE_ENTRY = _('Reset code')
71RESET_EMAIL_ENTRY = _('Email address')
72SET_NEW_PASSWORD_LABEL = _('A password reset code has been sent to ' \
73 '%(email)s.\nPlease enter the code below ' \
74 'along with your new password.')
75SET_UP_ACCOUNT_CHOICE_BUTTON = _('I don\'t have an account yet - sign me up')
76SET_UP_ACCOUNT_BUTTON = _('Set up Account')
77SIGN_IN_BUTTON = _('Sign In')
78SUCCESS = _('The process finished successfully. Congratulations!')
79SURNAME_ENTRY = _('Surname')
80TC_BUTTON = _('Show Terms & Conditions')
81TC_NOT_ACCEPTED = _('Agreeing to the Ubuntu One Terms & Conditions is ' \
82 'required to subscribe.')
83UNKNOWN_ERROR = _('There was an error when trying to complete the ' \
84 'process. Please check the information and try again.')
85VERIFY_EMAIL_TITLE = _('Enter verification code')
86VERIFY_EMAIL_CONTENT = _('Check %(email)s for an email from'
87 ' Ubuntu Single Sign On.'
88 ' This message contains a verification code.'
89 ' Enter the code in the field below and click OK'
90 ' to complete creating your %(app_name)s account')
91VERIFY_EMAIL_LABEL = ('<b>%s</b>\n\n' % VERIFY_EMAIL_TITLE +
92 VERIFY_EMAIL_CONTENT)
93YES_TO_TC = _('I agree with the %(app_name)s terms and conditions')
94YES_TO_UPDATES = _('Yes! Email me %(app_name)s tips and updates.')
95CAPTCHA_RELOAD_TOOLTIP = _('Reload')
96
3397
34def get_data_dir():98def get_data_dir():
35 """Build absolute path to the 'data' directory."""99 """Build absolute path to the 'data' directory."""
@@ -61,3 +125,46 @@
61def get_data_file(*args):125def get_data_file(*args):
62 """Build absolute path to the path within the 'data' directory."""126 """Build absolute path to the path within the 'data' directory."""
63 return os.path.join(get_data_dir(), *args)127 return os.path.join(get_data_dir(), *args)
128
129
130def get_password_strength(password):
131 """Return the strenght of the password.
132
133 This function returns the strenght of the password so that ui elements
134 can show the user how good his password is. The logic used is the
135 following:
136
137 * 1 extra point for 4 chars passwords
138 * 1 extra point for 8 chars passwords
139 * 1 extra point for more than 11 chars passwords.
140 * 1 extra point for passwords with at least one number.
141 * 1 extra point for passwords for lower and capital chars.
142 * 1 extra point for passwords with a special char.
143
144 A passwords starts with 0 and the extra points are added accordingly.
145 """
146 score = 0
147 if len(password) < 1:
148 return 0
149 if len(password) < 4:
150 score = 1
151 if len(password) >= 8:
152 score += 1
153 if len(password) >= 11:
154 score += 1
155 if re.search('\d+', password):
156 score += 1
157 if re.search('[a-z]', password) and re.search('[A-Z]', password):
158 score += 1
159 if re.search('.[!,@,#,$,%,^,&,*,?,_,~,-,£,(,)]', password):
160 score += 1
161 return score
162
163
164def is_min_required_password(password):
165 """Return if the password meets the minimum requirements."""
166 if (len(password) < 8 or
167 re.search('[A-Z]', password) is None or
168 re.search('\d+', password) is None):
169 return False
170 return True

Subscribers

People subscribed via source and target branches