Merge lp:~mardy/ubuntu-system-settings-online-accounts/qml-dialog into lp:~online-accounts/ubuntu-system-settings-online-accounts/master

Proposed by Alberto Mardegan
Status: Merged
Merged at revision: 203
Proposed branch: lp:~mardy/ubuntu-system-settings-online-accounts/qml-dialog
Merge into: lp:~online-accounts/ubuntu-system-settings-online-accounts/master
Diff against target: 588 lines (+492/-2)
7 files modified
debian/control (+1/-0)
online-accounts-ui/dialog-request.cpp (+286/-0)
online-accounts-ui/dialog-request.h (+54/-0)
online-accounts-ui/online-accounts-ui.pro (+3/-0)
online-accounts-ui/qml/SignOnUiDialog.qml (+115/-0)
online-accounts-ui/signonui-request.cpp (+32/-2)
online-accounts-ui/ui.qrc (+1/-0)
To merge this branch: bzr merge lp:~mardy/ubuntu-system-settings-online-accounts/qml-dialog
Reviewer Review Type Date Requested Status
David Barth (community) Approve
Review via email: mp+237970@code.launchpad.net

Commit message

Implement QML dialog for password queries

Authentication plugins can request SignOnUi to show a login form to the user. Support for this action is implemented by unity7's signon-ui, but was never implemented in this project.

Description of the change

Implement QML dialog for password queries

Authentication plugins can request SignOnUi to show a login form to the user. Support for this action is implemented by unity7's signon-ui, but was never implemented in this project.

Test case:
ubuntu-system-settings-online-accounts/password-query from https://wiki.ubuntu.com/Process/Merges/TestPlan/ubuntu-system-settings-online-accounts

To post a comment you must log in.
Revision history for this message
David Barth (dbarth) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2014-10-08 07:12:09 +0000
3+++ debian/control 2014-10-10 13:24:04 +0000
4@@ -6,6 +6,7 @@
5 pkg-config,
6 python3:any,
7 libaccounts-qt5-dev (>= 1.13),
8+ libapparmor-dev,
9 libclick-0.4-dev,
10 libmirclient-dev [!powerpc !ppc64 !ppc64el],
11 libnotify-dev,
12
13=== added file 'online-accounts-ui/dialog-request.cpp'
14--- online-accounts-ui/dialog-request.cpp 1970-01-01 00:00:00 +0000
15+++ online-accounts-ui/dialog-request.cpp 2014-10-10 13:24:04 +0000
16@@ -0,0 +1,286 @@
17+/*
18+ * This file is part of online-accounts-ui
19+ *
20+ * Copyright (C) 2014 Canonical Ltd.
21+ *
22+ * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
23+ *
24+ * This program is free software: you can redistribute it and/or modify it
25+ * under the terms of the GNU General Public License version 3, as published
26+ * by the Free Software Foundation.
27+ *
28+ * This program is distributed in the hope that it will be useful, but
29+ * WITHOUT ANY WARRANTY; without even the implied warranties of
30+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
31+ * PURPOSE. See the GNU General Public License for more details.
32+ *
33+ * You should have received a copy of the GNU General Public License along
34+ * with this program. If not, see <http://www.gnu.org/licenses/>.
35+ */
36+
37+#include "dialog-request.h"
38+
39+#include "debug.h"
40+#include "dialog.h"
41+#include "globals.h"
42+#include "i18n.h"
43+
44+#include <OnlineAccountsPlugin/request-handler.h>
45+#include <QDir>
46+#include <QQmlContext>
47+#include <QQmlEngine>
48+#include <SignOn/uisessiondata_priv.h>
49+
50+using namespace SignOnUi;
51+
52+/* These fields are temporarily defined here; they'll be eventually moved to
53+ * signond's include files. */
54+#define SSOUI_KEY_USERNAME_TEXT QLatin1String("UserNameText")
55+#define SSOUI_KEY_PASSWORD_TEXT QLatin1String("PasswordText")
56+#define SSOUI_KEY_REGISTER_URL QLatin1String("RegisterUrl")
57+#define SSOUI_KEY_REGISTER_TEXT QLatin1String("RegisterText")
58+#define SSOUI_KEY_LOGIN_TEXT QLatin1String("LoginText")
59+
60+namespace SignOnUi {
61+
62+class DialogRequestPrivate: public QObject
63+{
64+ Q_OBJECT
65+ Q_DECLARE_PUBLIC(DialogRequest)
66+ Q_PROPERTY(QString title READ title CONSTANT)
67+ Q_PROPERTY(QString userName READ userName WRITE setUserName \
68+ NOTIFY userNameChanged)
69+ Q_PROPERTY(QString password READ password WRITE setPassword \
70+ NOTIFY passwordChanged)
71+ Q_PROPERTY(QString userNameText READ userNameText CONSTANT)
72+ Q_PROPERTY(QString passwordText READ passwordText CONSTANT)
73+ Q_PROPERTY(QString message READ message CONSTANT)
74+ Q_PROPERTY(bool queryUserName READ queryUserName CONSTANT)
75+ Q_PROPERTY(bool queryPassword READ queryPassword CONSTANT)
76+ Q_PROPERTY(QUrl forgotPasswordUrl READ forgotPasswordUrl CONSTANT)
77+ Q_PROPERTY(QString forgotPasswordText READ forgotPasswordText CONSTANT)
78+ Q_PROPERTY(QUrl registerUrl READ registerUrl CONSTANT)
79+ Q_PROPERTY(QString registerText READ registerText CONSTANT)
80+ Q_PROPERTY(QString loginText READ loginText CONSTANT)
81+
82+public:
83+ DialogRequestPrivate(DialogRequest *request);
84+ ~DialogRequestPrivate();
85+
86+ void start();
87+
88+ QString title() const { return m_title; }
89+ void setUserName(const QString &userName);
90+ QString userName() const { return m_userName; }
91+ void setPassword(const QString &password);
92+ QString password() const { return m_password; }
93+ QString userNameText() const { return m_userNameText; }
94+ QString passwordText() const { return m_passwordText; }
95+ QString message() const { return m_message; }
96+ bool queryUserName() const { return m_queryUsername; }
97+ bool queryPassword() const { return m_queryPassword; }
98+ QUrl forgotPasswordUrl() const { return m_forgotPasswordUrl; }
99+ QString forgotPasswordText() const { return m_forgotPasswordText; }
100+ QUrl registerUrl() const { return m_registerUrl; }
101+ QString registerText() const { return m_registerText; }
102+ QString loginText() const { return m_loginText; }
103+
104+public Q_SLOTS:
105+ void cancel();
106+ void accept();
107+
108+Q_SIGNALS:
109+ void userNameChanged();
110+ void passwordChanged();
111+
112+private Q_SLOTS:
113+ void onFinished();
114+
115+private:
116+ void closeView();
117+
118+private:
119+ Dialog *m_dialog;
120+ QString m_title;
121+ QString m_userName;
122+ QString m_password;
123+ QString m_userNameText;
124+ QString m_passwordText;
125+ QString m_message;
126+ bool m_queryUsername;
127+ bool m_queryPassword;
128+ QUrl m_forgotPasswordUrl;
129+ QString m_forgotPasswordText;
130+ QUrl m_registerUrl;
131+ QString m_registerText;
132+ QString m_loginText;
133+ mutable DialogRequest *q_ptr;
134+};
135+
136+} // namespace
137+
138+DialogRequestPrivate::DialogRequestPrivate(DialogRequest *request):
139+ QObject(request),
140+ m_dialog(0),
141+ m_queryUsername(false),
142+ m_queryPassword(false),
143+ q_ptr(request)
144+{
145+ const QVariantMap &params = q_ptr->parameters();
146+
147+ if (params.contains(SSOUI_KEY_TITLE)) {
148+ m_title = params[SSOUI_KEY_TITLE].toString();
149+ } else if (params.contains(SSOUI_KEY_CAPTION)) {
150+ m_title = OnlineAccountsUi::_("Web authentication for %1",
151+ SIGNONUI_I18N_DOMAIN).
152+ arg(params[SSOUI_KEY_CAPTION].toString());
153+ } else {
154+ m_title = OnlineAccountsUi::_("Web authentication",
155+ SIGNONUI_I18N_DOMAIN);
156+ }
157+
158+ m_queryUsername = params.value(SSOUI_KEY_QUERYUSERNAME, false).toBool();
159+ m_userName = params.value(SSOUI_KEY_USERNAME).toString();
160+ m_userNameText = params.value(SSOUI_KEY_USERNAME_TEXT).toString();
161+ if (m_userNameText.isEmpty()) {
162+ m_userNameText = OnlineAccountsUi::_("Username:",
163+ SIGNONUI_I18N_DOMAIN);
164+ }
165+
166+ m_queryPassword = params.value(SSOUI_KEY_QUERYPASSWORD, false).toBool();
167+ m_password = params.value(SSOUI_KEY_PASSWORD).toString();
168+ m_passwordText = params.value(SSOUI_KEY_PASSWORD_TEXT).toString();
169+ if (m_passwordText.isEmpty()) {
170+ m_passwordText = OnlineAccountsUi::_("Password:",
171+ SIGNONUI_I18N_DOMAIN);
172+ }
173+
174+
175+ m_message = params.value(SSOUI_KEY_MESSAGE).toString();
176+
177+ m_forgotPasswordUrl =
178+ QUrl(params.value(SSOUI_KEY_FORGOTPASSWORDURL).toString());
179+ m_forgotPasswordText = params.value(SSOUI_KEY_FORGOTPASSWORD).toString();
180+
181+ m_registerUrl =
182+ QUrl(params.value(SSOUI_KEY_REGISTER_URL).toString());
183+ m_registerText = params.value(SSOUI_KEY_REGISTER_TEXT).toString();
184+
185+ m_loginText = params.value(SSOUI_KEY_LOGIN_TEXT).toString();
186+ if (m_loginText.isEmpty()) {
187+ m_loginText = OnlineAccountsUi::_("Sign in");
188+ }
189+}
190+
191+DialogRequestPrivate::~DialogRequestPrivate()
192+{
193+ closeView();
194+ delete m_dialog;
195+}
196+
197+void DialogRequestPrivate::start()
198+{
199+ Q_Q(DialogRequest);
200+
201+ const QVariantMap &params = q->parameters();
202+ DEBUG() << params;
203+
204+ if (!q->hasHandler()) {
205+ m_dialog = new Dialog;
206+ m_dialog->setTitle(m_title);
207+
208+ QObject::connect(m_dialog, SIGNAL(finished(int)),
209+ this, SLOT(onFinished()));
210+
211+ m_dialog->engine()->addImportPath(PLUGIN_PRIVATE_MODULE_DIR);
212+ m_dialog->rootContext()->setContextProperty("request", this);
213+ m_dialog->setSource(QUrl("qrc:/qml/SignOnUiDialog.qml"));
214+ q->setWindow(m_dialog);
215+ } else {
216+ DEBUG() << "Setting request on handler";
217+ q->handler()->setRequest(this);
218+ }
219+}
220+
221+void DialogRequestPrivate::accept()
222+{
223+ DEBUG() << "User accepted";
224+ onFinished();
225+}
226+
227+void DialogRequestPrivate::cancel()
228+{
229+ Q_Q(DialogRequest);
230+
231+ DEBUG() << "User requested to cancel";
232+ q->setCanceled();
233+ closeView();
234+}
235+
236+void DialogRequestPrivate::setUserName(const QString &userName)
237+{
238+ if (userName == m_userName) return;
239+ m_userName = userName;
240+ Q_EMIT userNameChanged();
241+}
242+
243+void DialogRequestPrivate::setPassword(const QString &password)
244+{
245+ if (password == m_password) return;
246+ m_password = password;
247+ Q_EMIT passwordChanged();
248+}
249+
250+void DialogRequestPrivate::onFinished()
251+{
252+ Q_Q(DialogRequest);
253+
254+ DEBUG() << "Dialog closed";
255+
256+ QVariantMap reply;
257+
258+ if (m_queryUsername) {
259+ reply[SSOUI_KEY_USERNAME] = m_userName;
260+ }
261+ if (m_queryPassword) {
262+ reply[SSOUI_KEY_PASSWORD] = m_password;
263+ }
264+
265+ closeView();
266+
267+ q->setResult(reply);
268+}
269+
270+void DialogRequestPrivate::closeView()
271+{
272+ Q_Q(DialogRequest);
273+
274+ if (q->hasHandler()) {
275+ q->handler()->setRequest(0);
276+ } else if (m_dialog) {
277+ m_dialog->close();
278+ }
279+}
280+
281+DialogRequest::DialogRequest(int id,
282+ const QString &clientProfile,
283+ const QVariantMap &parameters,
284+ QObject *parent):
285+ Request(id, clientProfile, parameters, parent),
286+ d_ptr(new DialogRequestPrivate(this))
287+{
288+}
289+
290+DialogRequest::~DialogRequest()
291+{
292+}
293+
294+void DialogRequest::start()
295+{
296+ Q_D(DialogRequest);
297+
298+ Request::start();
299+ d->start();
300+}
301+
302+#include "dialog-request.moc"
303
304=== added file 'online-accounts-ui/dialog-request.h'
305--- online-accounts-ui/dialog-request.h 1970-01-01 00:00:00 +0000
306+++ online-accounts-ui/dialog-request.h 2014-10-10 13:24:04 +0000
307@@ -0,0 +1,54 @@
308+/*
309+ * This file is part of online-accounts-ui
310+ *
311+ * Copyright (C) 2014 Canonical Ltd.
312+ *
313+ * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
314+ *
315+ * This program is free software: you can redistribute it and/or modify it
316+ * under the terms of the GNU General Public License version 3, as published
317+ * by the Free Software Foundation.
318+ *
319+ * This program is distributed in the hope that it will be useful, but
320+ * WITHOUT ANY WARRANTY; without even the implied warranties of
321+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
322+ * PURPOSE. See the GNU General Public License for more details.
323+ *
324+ * You should have received a copy of the GNU General Public License along
325+ * with this program. If not, see <http://www.gnu.org/licenses/>.
326+ */
327+
328+#ifndef SIGNON_UI_DIALOG_REQUEST_H
329+#define SIGNON_UI_DIALOG_REQUEST_H
330+
331+#include "signonui-request.h"
332+
333+#include <QObject>
334+
335+namespace SignOnUi {
336+
337+class DialogRequestPrivate;
338+
339+class DialogRequest: public Request
340+{
341+ Q_OBJECT
342+
343+public:
344+ explicit DialogRequest(int id,
345+ const QString &clientProfile,
346+ const QVariantMap &parameters,
347+ QObject *parent = 0);
348+ ~DialogRequest();
349+
350+ // reimplemented virtual methods
351+ void start();
352+
353+private:
354+ DialogRequestPrivate *d_ptr;
355+ Q_DECLARE_PRIVATE(DialogRequest)
356+};
357+
358+} // namespace
359+
360+#endif // SIGNON_UI_DIALOG_REQUEST_H
361+
362
363=== modified file 'online-accounts-ui/online-accounts-ui.pro'
364--- online-accounts-ui/online-accounts-ui.pro 2014-10-09 12:24:45 +0000
365+++ online-accounts-ui/online-accounts-ui.pro 2014-10-10 13:24:04 +0000
366@@ -17,6 +17,7 @@
367
368 PKGCONFIG += \
369 accounts-qt5 \
370+ libapparmor \
371 libnotify \
372 libsignon-qt5 \
373 signon-plugins-common
374@@ -44,6 +45,7 @@
375 browser-request.cpp \
376 debug.cpp \
377 dialog.cpp \
378+ dialog-request.cpp \
379 i18n.cpp \
380 ipc.cpp \
381 main.cpp \
382@@ -59,6 +61,7 @@
383 browser-request.h \
384 debug.h \
385 dialog.h \
386+ dialog-request.h \
387 i18n.h \
388 ipc.h \
389 notification.h \
390
391=== added file 'online-accounts-ui/qml/SignOnUiDialog.qml'
392--- online-accounts-ui/qml/SignOnUiDialog.qml 1970-01-01 00:00:00 +0000
393+++ online-accounts-ui/qml/SignOnUiDialog.qml 2014-10-10 13:24:04 +0000
394@@ -0,0 +1,115 @@
395+import QtQuick 2.0
396+import Ubuntu.Components 0.1
397+import Ubuntu.Components.ListItems 0.1 as ListItem
398+import Ubuntu.OnlineAccounts.Plugin 1.0
399+
400+MainView {
401+ id: root
402+
403+ property var signonRequest: request
404+
405+ width: units.gu(60)
406+ height: units.gu(90)
407+
408+ Page {
409+ title: signonRequest.title
410+
411+ Column {
412+ id: loginForm
413+ anchors.left: parent.left
414+ anchors.right: parent.right
415+
416+ ListItem.Caption {
417+ visible: signonRequest.message !== ""
418+ text: signonRequest.message
419+ }
420+
421+ Label {
422+ id: userNameLabel
423+ visible: signonRequest.queryUserName
424+ text: signonRequest.userNameText
425+ }
426+
427+ TextField {
428+ id: userNameField
429+ visible: signonRequest.queryUserName
430+ text: signonRequest.userName
431+ onTextChanged: signonRequest.userName = text
432+ }
433+
434+ Column {
435+ anchors.left: parent.left
436+ anchors.right: parent.right
437+ visible: signonRequest.queryPassword
438+
439+ Label {
440+ id: passwordLabel
441+ text: signonRequest.passwordText
442+ }
443+
444+ TextField {
445+ id: passwordField
446+ text: signonRequest.password
447+ echoMode: TextInput.Password
448+ onTextChanged: signonRequest.password = text
449+ Keys.onReturnPressed: signonRequest.accept()
450+ }
451+ Label {
452+ visible: signonRequest.forgotPasswordUrl.toString() !== ""
453+ text: "<a href=\"" + signonRequest.forgotPasswordUrl + "\">" +
454+ signonRequest.forgotPasswordText + "</a>"
455+ }
456+ }
457+ }
458+
459+ Item {
460+ anchors.left: parent.left
461+ anchors.right: parent.right
462+ anchors.top: loginForm.bottom
463+ anchors.bottom: pageFooter.top
464+
465+ Row {
466+ height: childrenRect.height
467+ anchors.left: parent.left
468+ anchors.right: parent.right
469+ anchors.bottom: parent.bottom
470+ spacing: units.gu(1)
471+
472+ Button {
473+ text: i18n.dtr("ubuntu-system-settings-online-accounts", "Cancel")
474+ width: (parent.width / 2) - 0.5 * parent.spacing
475+ onClicked: signonRequest.cancel()
476+ }
477+
478+ Button {
479+ text: signonRequest.loginText
480+ width: (parent.width / 2) - 0.5 * parent.spacing
481+ onClicked: signonRequest.accept()
482+ }
483+ }
484+ }
485+
486+ Item {
487+ id: pageFooter
488+ anchors.left: parent.left
489+ anchors.right: parent.right
490+ anchors.bottom: osk.top
491+ visible: signonRequest.registerUrl.toString() !== ""
492+
493+ ListItem.ThinDivider {
494+ anchors.bottom: registerUrlLabel.top
495+ }
496+
497+ Label {
498+ anchors.bottom: parent.bottom
499+ id: registerUrlLabel
500+ text: "<a href=\"" + signonRequest.registerUrl + "\">" +
501+ signonRequest.registerText + "</a>"
502+ }
503+ }
504+
505+ KeyboardRectangle {
506+ id: osk
507+ }
508+ }
509+}
510
511=== modified file 'online-accounts-ui/signonui-request.cpp'
512--- online-accounts-ui/signonui-request.cpp 2014-10-09 12:24:45 +0000
513+++ online-accounts-ui/signonui-request.cpp 2014-10-10 13:24:04 +0000
514@@ -22,6 +22,7 @@
515
516 #include "browser-request.h"
517 #include "debug.h"
518+#include "dialog-request.h"
519 #include "globals.h"
520 #include "notification.h"
521
522@@ -35,6 +36,7 @@
523 #include <QPointer>
524 #include <SignOn/uisessiondata.h>
525 #include <SignOn/uisessiondata_priv.h>
526+#include <sys/apparmor.h>
527
528 using namespace SignOnUi;
529
530@@ -203,16 +205,44 @@
531 return new SignOnUi::BrowserRequest(id, clientProfile,
532 parameters, parent);
533 } else {
534- return 0; // TODO new DialogRequest(connection, message, parameters, parent);
535+ return new SignOnUi::DialogRequest(id, clientProfile,
536+ parameters, parent);
537 }
538 }
539 #endif
540
541+static QString findClientProfile(const QString &clientProfile,
542+ const QVariantMap &parameters)
543+{
544+ QString profile = clientProfile;
545+ /* If the request is coming on the SignOnUi interface from an
546+ * unconfined process and it carries the SSOUI_KEY_PID key, it means that
547+ * it's coming from signond. In that case, we want to know what was the
548+ * client which originated the call.
549+ */
550+ if (profile == "unconfined" &&
551+ parameters.contains(SSOUI_KEY_PID)) {
552+ pid_t pid = parameters.value(SSOUI_KEY_PID).toUInt();
553+ char *con = NULL, *mode = NULL;
554+ int ret = aa_gettaskcon(pid, &con, &mode);
555+ if (Q_LIKELY(ret >= 0)) {
556+ profile = QString::fromUtf8(con);
557+ /* libapparmor allocates "con" and "mode" in a single allocation,
558+ * so freeing "con" is actually freeing both. */
559+ free(con);
560+ } else {
561+ qWarning() << "Couldn't get apparmor profile of PID" << pid;
562+ }
563+ }
564+ return profile;
565+}
566+
567 Request::Request(int id,
568 const QString &clientProfile,
569 const QVariantMap &parameters,
570 QObject *parent):
571- OnlineAccountsUi::Request(SIGNONUI_INTERFACE, id, clientProfile,
572+ OnlineAccountsUi::Request(SIGNONUI_INTERFACE, id,
573+ findClientProfile(clientProfile, parameters),
574 parameters, parent),
575 d_ptr(new RequestPrivate(this))
576 {
577
578=== modified file 'online-accounts-ui/ui.qrc'
579--- online-accounts-ui/ui.qrc 2014-08-13 14:39:53 +0000
580+++ online-accounts-ui/ui.qrc 2014-10-10 13:24:04 +0000
581@@ -3,6 +3,7 @@
582 <file>qml/AccountCreationPage.qml</file>
583 <file>qml/AuthorizationPage.qml</file>
584 <file>qml/ProviderRequest.qml</file>
585+ <file>qml/SignOnUiDialog.qml</file>
586 <file>qml/SignOnUiPage.qml</file>
587 </qresource>
588 </RCC>

Subscribers

People subscribed via source and target branches