Merge lp:~mardy/ubuntu-system-settings-online-accounts/empty-page-1594944 into lp:ubuntu-system-settings-online-accounts

Proposed by Alberto Mardegan
Status: Merged
Approved by: Alberto Mardegan
Approved revision: 372
Merged at revision: 391
Proposed branch: lp:~mardy/ubuntu-system-settings-online-accounts/empty-page-1594944
Merge into: lp:ubuntu-system-settings-online-accounts
Diff against target: 235 lines (+44/-45)
3 files modified
online-accounts-ui/provider-request.cpp (+29/-26)
online-accounts-ui/qml/ProviderRequest.qml (+12/-17)
tests/online-accounts-ui/tst_provider_request.cpp (+3/-2)
To merge this branch: bzr merge lp:~mardy/ubuntu-system-settings-online-accounts/empty-page-1594944
Reviewer Review Type Date Requested Status
dobey (community) Needs Fixing
PS Jenkins bot continuous-integration Pending
Review via email: mp+298123@code.launchpad.net

Commit message

Properly handle early termination of account access requests

When a degenerate request (coming from an unconfined process with empty application ID) was received, the allowed() signal was emitted from the Component.onCompleted handler.
However, given that this all was happening inside the QQuickView::setSource() method, the signal was effectively emitted before the C++ code had a chance to setup the signal connections, with the result that such a signal was lost.

To solve this, we export a "request" object to QML, whose methods replace the old signals.

Description of the change

Properly handle early termination of account access requests

When a degenerate request (coming from an unconfined process with empty application ID) was received, the allowed() signal was emitted from the Component.onCompleted handler.
However, given that this all was happening inside the QQuickView::setSource() method, the signal was effectively emitted before the C++ code had a chance to setup the signal connections, with the result that such a signal was lost.

To solve this, we export a "request" object to QML, whose methods replace the old signals.

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

I've build this in the silo where I have the ubuntuone-credentials changes, and a blank window is still opened, so this doesn't seem to resolve the bug.

Also, I was trying to find where this file exists on disk, so I could edit in place instead of building a silo, given it's a trivial change, however I do not see this file being installed to the system at all. Is it only included as a resource in Qt?

review: Needs Fixing
368. By Alberto Mardegan

Expose request to QML

369. By Alberto Mardegan

Avoid using context properties

370. By Alberto Mardegan

Don't connect to inexistent signal

371. By Alberto Mardegan

revert

372. By Alberto Mardegan

Update tst_provider_request

Revision history for this message
Alberto Mardegan (mardy) wrote :

Update.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'online-accounts-ui/provider-request.cpp'
2--- online-accounts-ui/provider-request.cpp 2015-11-18 08:27:12 +0000
3+++ online-accounts-ui/provider-request.cpp 2016-06-23 13:59:19 +0000
4@@ -41,6 +41,8 @@
5 {
6 Q_OBJECT
7 Q_DECLARE_PUBLIC(ProviderRequest)
8+ Q_PROPERTY(QVariantMap application READ applicationInfo CONSTANT)
9+ Q_PROPERTY(QVariantMap provider READ providerInfo CONSTANT)
10
11 public:
12 ProviderRequestPrivate(ProviderRequest *request);
13@@ -48,18 +50,21 @@
14
15 void start();
16
17+ QVariantMap applicationInfo() const { return m_applicationInfo; }
18+ QVariantMap providerInfo() const { return m_providerInfo; }
19+
20+public Q_SLOTS:
21+ void deny();
22+ void allow(int accountId);
23+
24 private Q_SLOTS:
25 void onWindowVisibleChanged(bool visible);
26- void onDenied();
27- void onAllowed(int accountId);
28-
29-private:
30- QVariantMap providerInfo(const QString &providerId) const;
31
32 private:
33 mutable ProviderRequest *q_ptr;
34 QQuickView *m_view;
35 QVariantMap m_applicationInfo;
36+ QVariantMap m_providerInfo;
37 };
38
39 } // namespace
40@@ -112,7 +117,7 @@
41 } else {
42 providerId = q->parameters().value(OAU_KEY_PROVIDER).toString();
43 }
44- QVariantMap providerInfo = appManager->providerInfo(providerId);
45+ m_providerInfo = appManager->providerInfo(providerId);
46
47 m_view = new QQuickView;
48 QObject::connect(m_view, SIGNAL(visibleChanged(bool)),
49@@ -126,7 +131,7 @@
50 * <package-dir>/lib/<DEB_HOST_MULTIARCH>
51 * to the QML import path.
52 */
53- QString packageDir = providerInfo.value("package-dir").toString();
54+ QString packageDir = m_providerInfo.value("package-dir").toString();
55 if (!packageDir.isEmpty()) {
56 engine->addImportPath(packageDir + "/lib");
57 #ifdef DEB_HOST_MULTIARCH
58@@ -142,22 +147,15 @@
59 QUrl::fromLocalFile(QStandardPaths::writableLocation(
60 QStandardPaths::GenericDataLocation) +
61 "/accounts/qml-plugins/"));
62- context->setContextProperty("provider", providerInfo);
63- context->setContextProperty("application", m_applicationInfo);
64+ context->setContextProperty("request", this);
65 context->setContextProperty("mainWindow", m_view);
66
67 m_view->setSource(QUrl(QStringLiteral("qrc:/qml/ProviderRequest.qml")));
68- QQuickItem *root = m_view->rootObject();
69- QObject::connect(root, SIGNAL(denied()),
70- this, SLOT(onDenied()));
71- QObject::connect(root, SIGNAL(allowed(int)),
72- this, SLOT(onAllowed(int)));
73- if (root->property("wasDenied").toBool()) {
74- DEBUG() << "Was denied";
75- q->setResult(QVariantMap());
76- return;
77+ /* It could be that allow() or deny() have been already called; don't show
78+ * the window in that case. */
79+ if (q->isInProgress()) {
80+ q->setWindow(m_view);
81 }
82- q->setWindow(m_view);
83 }
84
85 void ProviderRequestPrivate::onWindowVisibleChanged(bool visible)
86@@ -171,22 +169,27 @@
87 }
88 }
89
90-void ProviderRequestPrivate::onDenied()
91+void ProviderRequestPrivate::deny()
92 {
93+ Q_Q(ProviderRequest);
94 DEBUG();
95- /* Just close the window; this will deliver the empty result to the
96- * client */
97- m_view->close();
98+ if (m_view->isVisible()) {
99+ /* Just close the window; this will deliver the empty result to the
100+ * client */
101+ m_view->close();
102+ } else {
103+ q->setResult(QVariantMap());
104+ }
105 }
106
107-void ProviderRequestPrivate::onAllowed(int accountId)
108+void ProviderRequestPrivate::allow(int accountId)
109 {
110 Q_Q(ProviderRequest);
111 DEBUG() << "Access allowed for account:" << accountId;
112 /* If the request came from an app, add a small delay so that we could
113 * serve an authentication request coming right after this one. */
114- if (m_applicationInfo.value("id").toString() !=
115- QStringLiteral("system-settings")) {
116+ if (m_view->isVisible() &&
117+ m_applicationInfo.value("id").toString() != "system-settings") {
118 q->setDelay(3000);
119 }
120 QVariantMap result;
121
122=== modified file 'online-accounts-ui/qml/ProviderRequest.qml'
123--- online-accounts-ui/qml/ProviderRequest.qml 2016-05-19 11:06:28 +0000
124+++ online-accounts-ui/qml/ProviderRequest.qml 2016-06-23 13:59:19 +0000
125@@ -24,14 +24,10 @@
126 MainView {
127 id: root
128
129- property variant applicationInfo: application
130- property variant providerInfo: provider
131- property bool wasDenied: false
132+ property var applicationInfo: request.application
133+ property var providerInfo: request.provider
134 property int __createdAccountId: 0
135
136- signal denied
137- signal allowed(int accountId)
138-
139 width: units.gu(48)
140 height: units.gu(60)
141 automaticOrientation: true
142@@ -40,14 +36,14 @@
143 i18n.domain = "ubuntu-system-settings-online-accounts"
144 if (accessModel.count === 0 && !accessModel.canCreateAccounts) {
145 /* No accounts to authorize */
146- denied()
147+ request.deny()
148 return
149 }
150- if (!application.id && accessModel.count == 1 &&
151+ if (!applicationInfo.id && accessModel.count == 1 &&
152 applicationInfo.profile == "unconfined") {
153 /* Degenerate case: unconfined app making requests with no valid
154 * app ID */
155- allowed(accountsModel.get(0, "accountId"))
156+ request.allow(accountsModel.get(0, "accountId"))
157 return
158 }
159 loader.active = true
160@@ -55,9 +51,6 @@
161 }
162
163 on__CreatedAccountIdChanged: grantAccessIfReady()
164- onDenied: wasDenied = true
165-
166- onAllowed: loader.sourceComponent = spinnerComponent
167
168 PageStack {
169 id: pageStack
170@@ -111,7 +104,7 @@
171 AccountCreationPage {
172 providerId: providerInfo.id
173 onFinished: {
174- if (accountId == 0) root.denied()
175+ if (accountId == 0) request.deny()
176 /* if an account was created, just remember its ID. when the
177 * accountsModel will notice it we'll proceed with the access
178 * grant */
179@@ -127,7 +120,7 @@
180 application: applicationInfo
181 provider: providerInfo
182 canAddAnotherAccount: accessModel.canCreateAccounts
183- onDenied: root.denied()
184+ onDenied: request.deny()
185 onAllowed: root.grantAccess(accountId)
186 onCreateAccount: pageStack.push(createAccountPageComponent)
187 }
188@@ -198,7 +191,8 @@
189 if (root.__createdAccountId != 0) {
190 // If the request comes from system settings, stop here
191 if (applicationInfo.id === "system-settings") {
192- root.allowed(root.__createdAccountId)
193+ request.allow(root.__createdAccountId)
194+ loader.sourceComponent = spinnerComponent
195 return
196 }
197
198@@ -216,7 +210,7 @@
199 if (i < 0) {
200 // very unlikely; maybe the account has been deleted in the meantime
201 console.log("Account not found:" + accountId)
202- root.denied()
203+ request.deny()
204 return
205 }
206
207@@ -249,6 +243,7 @@
208
209 function accountEnablingDone() {
210 console.log("account enabling done")
211- allowed(account.accountId)
212+ request.allow(account.accountId)
213+ loader.sourceComponent = spinnerComponent
214 }
215 }
216
217=== modified file 'tests/online-accounts-ui/tst_provider_request.cpp'
218--- tests/online-accounts-ui/tst_provider_request.cpp 2015-06-23 13:17:10 +0000
219+++ tests/online-accounts-ui/tst_provider_request.cpp 2016-06-23 13:59:19 +0000
220@@ -173,12 +173,13 @@
221 QTRY_COMPARE(setWindowCalled.count(), 1);
222 QQuickView *view = static_cast<QQuickView*>(setWindowCalled.at(0).at(0).value<QWindow*>());
223 QQmlContext *context = view->engine()->rootContext();
224+ QObject *request = context->contextProperty("request").value<QObject*>();
225
226 QCOMPARE(applicationInfoCalled.count(), 1);
227 QCOMPARE(applicationInfoCalled.at(0).at(1).toString(), profile);
228
229- QCOMPARE(context->contextProperty("provider").toMap(), providerInfo);
230- QCOMPARE(context->contextProperty("application").toMap(), applicationInfo);
231+ QCOMPARE(request->property("provider").toMap(), providerInfo);
232+ QCOMPARE(request->property("application").toMap(), applicationInfo);
233 } else {
234 QTRY_COMPARE(failCalled.count(), 1);
235 QCOMPARE(failCalled.at(0).at(0).toString(), errorName);

Subscribers

People subscribed via source and target branches