Merge lp:~mardy/online-accounts-api/providers-1627001 into lp:online-accounts-api
- providers-1627001
- Merge into trunk
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Alberto Mardegan | ||||||||
Approved revision: | 52 | ||||||||
Merged at revision: | 38 | ||||||||
Proposed branch: | lp:~mardy/online-accounts-api/providers-1627001 | ||||||||
Merge into: | lp:online-accounts-api | ||||||||
Diff against target: |
1839 lines (+826/-80) 34 files modified
debian/control (+1/-1) src/lib/OnlineAccounts/CMakeLists.txt (+2/-0) src/lib/OnlineAccounts/Service (+1/-0) src/lib/OnlineAccounts/account.cpp (+11/-0) src/lib/OnlineAccounts/account.h (+3/-0) src/lib/OnlineAccounts/account_p.h (+2/-0) src/lib/OnlineAccounts/dbus_interface.cpp (+2/-0) src/lib/OnlineAccounts/manager.cpp (+14/-1) src/lib/OnlineAccounts/manager.h (+6/-1) src/lib/OnlineAccounts/manager_p.h (+6/-0) src/lib/OnlineAccounts/service.cpp (+54/-0) src/lib/OnlineAccounts/service.h (+83/-0) src/lib/OnlineAccountsDaemon/CMakeLists.txt (+1/-0) src/lib/OnlineAccountsDaemon/com.ubuntu.OnlineAccounts.Manager.xml (+14/-0) src/lib/OnlineAccountsDaemon/dbus_constants.h (+3/-0) src/lib/OnlineAccountsDaemon/i18n.cpp (+34/-0) src/lib/OnlineAccountsDaemon/i18n.h (+32/-0) src/lib/OnlineAccountsDaemon/manager.cpp (+86/-10) src/lib/OnlineAccountsDaemon/manager.h (+2/-1) src/lib/OnlineAccountsDaemon/manager_adaptor.cpp (+7/-3) src/lib/OnlineAccountsDaemon/manager_adaptor.h (+4/-1) src/lib/Ubuntu/OnlineAccounts.2/account.cpp (+34/-4) src/lib/Ubuntu/OnlineAccounts.2/account.h (+10/-1) src/lib/Ubuntu/OnlineAccounts.2/account_model.cpp (+28/-1) src/lib/Ubuntu/OnlineAccounts.2/account_model.h (+9/-0) src/lib/Ubuntu/OnlineAccounts.2/plugin.cpp (+5/-0) tests/daemon/functional_tests/data/com.ubuntu.tests_application.application (+4/-1) tests/daemon/functional_tests/data/com.ubuntu.tests_coolshare.service (+1/-1) tests/daemon/functional_tests/data/coolmail.service (+0/-1) tests/daemon/functional_tests/data/missing-provider.service (+14/-0) tests/daemon/functional_tests/functional_tests.cpp (+133/-10) tests/daemon/functional_tests/test_process.py (+5/-2) tests/lib/OnlineAccounts/functional_tests/functional_tests.cpp (+108/-22) tests/lib/qml_module/tst_qml_module.cpp (+107/-19) |
||||||||
To merge this branch: | bzr merge lp:~mardy/online-accounts-api/providers-1627001 | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexandre Abreu (community) | Approve | ||
Review via email:
|
Commit message
Add provider information to public API
Allow clients to retrieve the list of available service providers, consisting of translated display name and icon URL.
Also, add a service() method to the Account class, to get the data associated with each account.
Description of the change
Add provider information to public API
Allow clients to retrieve the list of available service providers, consisting of translated display name and icon URL.
Also, add a service() method to the Account class, to get the data associated with each account.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Michi Henning (michihenning) wrote : | # |
- 35. By Alberto Mardegan
-
Bump dependency on libaccounts-qt
- 36. By Alberto Mardegan
-
Add missing files
- 37. By Alberto Mardegan
-
DOn't use qjsEngine() it doesn't exist in QT 5.4
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Alberto Mardegan (mardy) wrote : | # |
> I may be missing something here, but (not being familiar with the code), it
> looks like the translated service name is not present? We need the translated
> name of the service too (such as "Google" or "Dropbox", or their equivalents
> in Arabic script, or whatever).
It's there, line 549 of the diff. I'll soon prepare a test app to verify that everything is place, in case unit tests are not catching everything.
- 38. By Alberto Mardegan
-
more of the same
- 39. By Alberto Mardegan
-
Cast QList<QString> to QStringList
- 40. By Alberto Mardegan
-
Don't use Q_GADGET functionality in Qt < 5.5
- 41. By Alberto Mardegan
-
Fix typo
- 42. By Alberto Mardegan
-
type conv for qt 5.4
- 43. By Alberto Mardegan
-
fix
- 44. By Alberto Mardegan
-
skip test
- 45. By Alberto Mardegan
-
fix
- 46. By Alberto Mardegan
-
Fallback to provider's icon and display name
- 47. By Alberto Mardegan
-
test debugging
- 48. By Alberto Mardegan
-
fix test
- 49. By Alberto Mardegan
-
remove debugging
- 50. By Alberto Mardegan
-
Don't crash if serviceList property is retrieved when the model is not ready
With this fix, we also need a signal to inform the QML engine of when the
property becomes available - 51. By Alberto Mardegan
-
Skip missing providers
- 52. By Alberto Mardegan
-
Expose enums to QML
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Alberto Mardegan (mardy) wrote : | # |
This is implemented and available for testing here: https:/
See the "Test plan" in that silo for a quick way to test it.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Alexandre Abreu (abreu-alexandre) wrote : | # |
LGTM
one inlined question
- 53. By Alberto Mardegan
-
Remove commented line
Preview Diff
1 | === modified file 'debian/control' |
2 | --- debian/control 2016-10-03 07:46:50 +0000 |
3 | +++ debian/control 2016-11-10 09:12:06 +0000 |
4 | @@ -6,7 +6,7 @@ |
5 | debhelper (>= 9), |
6 | pkg-config, |
7 | python3:any, |
8 | - libaccounts-qt5-dev, |
9 | + libaccounts-qt5-dev (>= 1.15), |
10 | libapparmor-dev, |
11 | libonline-accounts-client-dev (>= 0.7), |
12 | libqtdbusmock1-dev, |
13 | |
14 | === modified file 'src/lib/OnlineAccounts/CMakeLists.txt' |
15 | --- src/lib/OnlineAccounts/CMakeLists.txt 2016-11-01 09:48:22 +0000 |
16 | +++ src/lib/OnlineAccounts/CMakeLists.txt 2016-11-10 09:12:06 +0000 |
17 | @@ -22,6 +22,7 @@ |
18 | manager.cpp |
19 | pending_call.cpp |
20 | request_access_reply.cpp |
21 | + service.cpp |
22 | ) |
23 | set_target_properties(${CLIENT_LIB} PROPERTIES |
24 | VERSION 1.0.0 |
25 | @@ -52,5 +53,6 @@ |
26 | PasswordData |
27 | PendingCall pending_call.h |
28 | PendingCallWatcher |
29 | + Service service.h |
30 | DESTINATION include/${CLIENT_LIB}/OnlineAccounts |
31 | ) |
32 | |
33 | === added file 'src/lib/OnlineAccounts/Service' |
34 | --- src/lib/OnlineAccounts/Service 1970-01-01 00:00:00 +0000 |
35 | +++ src/lib/OnlineAccounts/Service 2016-11-10 09:12:06 +0000 |
36 | @@ -0,0 +1,1 @@ |
37 | +#include "service.h" |
38 | |
39 | === modified file 'src/lib/OnlineAccounts/account.cpp' |
40 | --- src/lib/OnlineAccounts/account.cpp 2015-08-26 13:32:38 +0000 |
41 | +++ src/lib/OnlineAccounts/account.cpp 2016-11-10 09:12:06 +0000 |
42 | @@ -53,6 +53,11 @@ |
43 | } |
44 | } |
45 | |
46 | +Service AccountPrivate::service() const |
47 | +{ |
48 | + return m_manager->d_ptr->service(m_info.service()); |
49 | +} |
50 | + |
51 | Account::Account(AccountPrivate *priv, QObject *parent): |
52 | QObject(parent), |
53 | d_ptr(priv) |
54 | @@ -72,6 +77,12 @@ |
55 | return d->m_isValid; |
56 | } |
57 | |
58 | +Service Account::service() const |
59 | +{ |
60 | + Q_D(const Account); |
61 | + return d->service(); |
62 | +} |
63 | + |
64 | AccountId Account::id() const |
65 | { |
66 | Q_D(const Account); |
67 | |
68 | === modified file 'src/lib/OnlineAccounts/account.h' |
69 | --- src/lib/OnlineAccounts/account.h 2015-08-26 13:32:38 +0000 |
70 | +++ src/lib/OnlineAccounts/account.h 2016-11-10 09:12:06 +0000 |
71 | @@ -26,6 +26,7 @@ |
72 | |
73 | #include "global.h" |
74 | #include "pending_call.h" |
75 | +#include "service.h" |
76 | |
77 | namespace OnlineAccounts { |
78 | |
79 | @@ -43,6 +44,8 @@ |
80 | /* Returns false if account deleted or disabled */ |
81 | bool isValid() const; |
82 | |
83 | + Service service() const; |
84 | + |
85 | AccountId id() const; |
86 | QString displayName() const; |
87 | QString serviceId() const; |
88 | |
89 | === modified file 'src/lib/OnlineAccounts/account_p.h' |
90 | --- src/lib/OnlineAccounts/account_p.h 2015-03-04 10:01:32 +0000 |
91 | +++ src/lib/OnlineAccounts/account_p.h 2016-11-10 09:12:06 +0000 |
92 | @@ -37,6 +37,8 @@ |
93 | void setInvalid(); |
94 | void update(const AccountInfo &info); |
95 | |
96 | + Service service() const; |
97 | + |
98 | private: |
99 | Manager *m_manager; |
100 | AccountInfo m_info; |
101 | |
102 | === modified file 'src/lib/OnlineAccounts/dbus_interface.cpp' |
103 | --- src/lib/OnlineAccounts/dbus_interface.cpp 2015-03-03 07:09:50 +0000 |
104 | +++ src/lib/OnlineAccounts/dbus_interface.cpp 2016-11-10 09:12:06 +0000 |
105 | @@ -22,6 +22,7 @@ |
106 | |
107 | #include <QDBusMetaType> |
108 | #include <QDebug> |
109 | +#include <QVariantMap> |
110 | #include <climits> |
111 | |
112 | using namespace OnlineAccounts; |
113 | @@ -37,6 +38,7 @@ |
114 | |
115 | qDBusRegisterMetaType<AccountInfo>(); |
116 | qDBusRegisterMetaType<QList<AccountInfo>>(); |
117 | + qDBusRegisterMetaType<QList<QVariantMap>>(); |
118 | |
119 | bool ok = connect("AccountChanged", "s(ua{sv})", |
120 | this, SLOT(onAccountChanged(const QString&,const OnlineAccounts::AccountInfo&))); |
121 | |
122 | === modified file 'src/lib/OnlineAccounts/manager.cpp' |
123 | --- src/lib/OnlineAccounts/manager.cpp 2016-11-01 09:48:22 +0000 |
124 | +++ src/lib/OnlineAccounts/manager.cpp 2016-11-10 09:12:06 +0000 |
125 | @@ -45,6 +45,7 @@ |
126 | q_ptr(q) |
127 | { |
128 | qRegisterMetaType<Account*>(); |
129 | + qRegisterMetaType<Service>("OnlineAccounts::Service"); |
130 | |
131 | QObject::connect(&m_daemon, |
132 | SIGNAL(accountChanged(const QString&, const OnlineAccounts::AccountInfo&)), |
133 | @@ -125,7 +126,7 @@ |
134 | |
135 | Q_ASSERT(m_getAccountsCall); |
136 | |
137 | - QDBusPendingReply<QList<AccountInfo> > reply = *m_getAccountsCall; |
138 | + QDBusPendingReply<QList<AccountInfo>,QList<QVariantMap>> reply = *m_getAccountsCall; |
139 | if (Q_UNLIKELY(reply.isError())) { |
140 | qCWarning(DBG_ONLINE_ACCOUNTS) << "GetAccounts call failed:" << |
141 | reply.error(); |
142 | @@ -136,6 +137,12 @@ |
143 | Q_FOREACH(const AccountInfo &info, accountInfos) { |
144 | m_accounts.insert({info.id(), info.service()}, AccountData(info)); |
145 | } |
146 | + |
147 | + QList<QVariantMap> services = reply.argumentAt<1>(); |
148 | + for (const QVariantMap &data: services) { |
149 | + Service service(new Service::ServiceData(data)); |
150 | + m_services.insert(service.id(), service); |
151 | + } |
152 | } |
153 | m_getAccountsCall->deleteLater(); |
154 | m_getAccountsCall = 0; |
155 | @@ -197,6 +204,12 @@ |
156 | } |
157 | } |
158 | |
159 | +QList<Service> Manager::availableServices() const |
160 | +{ |
161 | + Q_D(const Manager); |
162 | + return d->m_services.values(); |
163 | +} |
164 | + |
165 | QList<Account*> Manager::availableAccounts(const QString &service) |
166 | { |
167 | Q_D(Manager); |
168 | |
169 | === modified file 'src/lib/OnlineAccounts/manager.h' |
170 | --- src/lib/OnlineAccounts/manager.h 2016-07-22 05:08:06 +0000 |
171 | +++ src/lib/OnlineAccounts/manager.h 2016-11-10 09:12:06 +0000 |
172 | @@ -27,12 +27,14 @@ |
173 | #include "error.h" |
174 | #include "global.h" |
175 | #include "pending_call.h" |
176 | +#include "service.h" |
177 | |
178 | class QDBusConnection; |
179 | |
180 | namespace OnlineAccounts { |
181 | |
182 | class Account; |
183 | +class AccountPrivate; |
184 | class AuthenticationData; |
185 | class RequestAccessReplyPrivate; |
186 | |
187 | @@ -44,12 +46,14 @@ |
188 | public: |
189 | explicit Manager(const QString &applicationId, QObject *parent = 0); |
190 | Manager(const QString &applicationId, const QDBusConnection &bus, |
191 | - QObject *parent = 0); |
192 | + QObject *parent = 0); |
193 | ~Manager(); |
194 | |
195 | bool isReady() const; |
196 | void waitForReady(); |
197 | |
198 | + QList<Service> availableServices() const; |
199 | + |
200 | QList<Account*> availableAccounts(const QString &service = QString()); |
201 | Account *account(AccountId accountId); |
202 | Account *account(AccountId accountId, const QString &service); |
203 | @@ -63,6 +67,7 @@ |
204 | |
205 | private: |
206 | friend class Account; |
207 | + friend class AccountPrivate; |
208 | friend class RequestAccessReplyPrivate; |
209 | Q_DECLARE_PRIVATE(Manager) |
210 | Q_DISABLE_COPY(Manager) |
211 | |
212 | === modified file 'src/lib/OnlineAccounts/manager_p.h' |
213 | --- src/lib/OnlineAccounts/manager_p.h 2016-07-22 05:08:06 +0000 |
214 | +++ src/lib/OnlineAccounts/manager_p.h 2016-11-10 09:12:06 +0000 |
215 | @@ -58,6 +58,11 @@ |
216 | |
217 | Account *ensureAccount(const AccountInfo &info); |
218 | |
219 | + static Service serviceFromMap(const QVariantMap &map); |
220 | + Service service(const QString &serviceId) { |
221 | + return m_services.value(serviceId); |
222 | + } |
223 | + |
224 | private: |
225 | void retrieveAccounts(); |
226 | |
227 | @@ -71,6 +76,7 @@ |
228 | DBusInterface m_daemon; |
229 | QDBusPendingCallWatcher *m_getAccountsCall; |
230 | QMap<QPair<AccountId,QString>,AccountData> m_accounts; |
231 | + QMap<QString,Service> m_services; |
232 | mutable Manager *q_ptr; |
233 | }; |
234 | |
235 | |
236 | === added file 'src/lib/OnlineAccounts/service.cpp' |
237 | --- src/lib/OnlineAccounts/service.cpp 1970-01-01 00:00:00 +0000 |
238 | +++ src/lib/OnlineAccounts/service.cpp 2016-11-10 09:12:06 +0000 |
239 | @@ -0,0 +1,54 @@ |
240 | +/* |
241 | + * This file is part of libOnlineAccounts |
242 | + * |
243 | + * Copyright (C) 2016 Canonical Ltd. |
244 | + * |
245 | + * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> |
246 | + * |
247 | + * This program is free software: you can redistribute it and/or modify it |
248 | + * under the terms of the GNU Lesser General Public License version 3, as |
249 | + * published by the Free Software Foundation. |
250 | + * |
251 | + * This program is distributed in the hope that it will be useful, but |
252 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
253 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
254 | + * PURPOSE. See the GNU Lesser General Public License for more details. |
255 | + * |
256 | + * You should have received a copy of the GNU Lesser General Public License |
257 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
258 | + */ |
259 | + |
260 | +#include "service.h" |
261 | + |
262 | +#include <QVariantMap> |
263 | +#include "OnlineAccountsDaemon/dbus_constants.h" |
264 | + |
265 | +using namespace OnlineAccounts; |
266 | + |
267 | +Service::ServiceData::ServiceData(const QVariantMap &map): |
268 | + m_id(map.value(ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID).toString()), |
269 | + m_displayName(map.value(ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME).toString()), |
270 | + m_iconSource(map.value(ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE).toString()) |
271 | +{ |
272 | +} |
273 | + |
274 | +Service::Service(): |
275 | + d(new ServiceData(QVariantMap())) |
276 | +{ |
277 | +} |
278 | + |
279 | +Service::Service(const QVariantMap &map): |
280 | + d(new ServiceData(map)) |
281 | +{ |
282 | +} |
283 | + |
284 | +#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) |
285 | +QVariantMap Service::toMap() const |
286 | +{ |
287 | + return QVariantMap { |
288 | + { "serviceId", id() }, |
289 | + { "displayName", displayName() }, |
290 | + { "iconSource", iconSource() }, |
291 | + }; |
292 | +} |
293 | +#endif |
294 | |
295 | === added file 'src/lib/OnlineAccounts/service.h' |
296 | --- src/lib/OnlineAccounts/service.h 1970-01-01 00:00:00 +0000 |
297 | +++ src/lib/OnlineAccounts/service.h 2016-11-10 09:12:06 +0000 |
298 | @@ -0,0 +1,83 @@ |
299 | +/* |
300 | + * This file is part of libOnlineAccounts |
301 | + * |
302 | + * Copyright (C) 2016 Canonical Ltd. |
303 | + * |
304 | + * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> |
305 | + * |
306 | + * This program is free software: you can redistribute it and/or modify it |
307 | + * under the terms of the GNU Lesser General Public License version 3, as |
308 | + * published by the Free Software Foundation. |
309 | + * |
310 | + * This program is distributed in the hope that it will be useful, but |
311 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
312 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
313 | + * PURPOSE. See the GNU Lesser General Public License for more details. |
314 | + * |
315 | + * You should have received a copy of the GNU Lesser General Public License |
316 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
317 | + */ |
318 | + |
319 | +#ifndef ONLINE_ACCOUNTS_SERVICE_H |
320 | +#define ONLINE_ACCOUNTS_SERVICE_H |
321 | + |
322 | +#include <QObject> |
323 | +#include <QSharedData> |
324 | +#include <QSharedDataPointer> |
325 | +#include <QUrl> |
326 | +#include <QVariantMap> |
327 | + |
328 | +#include "global.h" |
329 | + |
330 | +namespace OnlineAccounts { |
331 | + |
332 | +class Manager; |
333 | +class ManagerPrivate; |
334 | + |
335 | +class ONLINE_ACCOUNTS_EXPORT Service |
336 | +{ |
337 | + Q_GADGET |
338 | + Q_PROPERTY(QString serviceId READ id CONSTANT) |
339 | + Q_PROPERTY(QString displayName READ displayName CONSTANT) |
340 | + Q_PROPERTY(QUrl iconSource READ iconSource CONSTANT) |
341 | + |
342 | +private: |
343 | + class ServiceData: public QSharedData { |
344 | + ServiceData(const QVariantMap &map); |
345 | + friend class ManagerPrivate; |
346 | + friend class Service; |
347 | + QString m_id; |
348 | + QString m_displayName; |
349 | + QUrl m_iconSource; |
350 | + }; |
351 | + |
352 | +public: |
353 | + Service(); |
354 | + ~Service() {} |
355 | + |
356 | + Service(const Service &other): d(other.d) {} |
357 | + |
358 | + bool isValid() const { return !d->m_id.isEmpty(); } |
359 | + QString id() const { return d->m_id; } |
360 | + QString displayName() const { return d->m_displayName; } |
361 | + QUrl iconSource() const { return d->m_iconSource; } |
362 | + |
363 | +#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0) |
364 | + QVariantMap toMap() const; |
365 | +#endif |
366 | + |
367 | +protected: |
368 | + Service(const QVariantMap &map); |
369 | + |
370 | +private: |
371 | + friend class Manager; |
372 | + friend class ManagerPrivate; |
373 | + Service(ServiceData *d): d(d) {}; |
374 | + QSharedDataPointer<ServiceData> d; |
375 | +}; |
376 | + |
377 | +} // namespace |
378 | + |
379 | +Q_DECLARE_METATYPE(OnlineAccounts::Service) |
380 | + |
381 | +#endif // ONLINE_ACCOUNTS_SERVICE_H |
382 | |
383 | === modified file 'src/lib/OnlineAccountsDaemon/CMakeLists.txt' |
384 | --- src/lib/OnlineAccountsDaemon/CMakeLists.txt 2015-09-04 08:32:00 +0000 |
385 | +++ src/lib/OnlineAccountsDaemon/CMakeLists.txt 2016-11-10 09:12:06 +0000 |
386 | @@ -23,6 +23,7 @@ |
387 | authentication_request.cpp |
388 | authenticator.cpp |
389 | client_registry.cpp |
390 | + i18n.cpp |
391 | manager.cpp |
392 | manager_adaptor.cpp |
393 | state_saver.cpp |
394 | |
395 | === modified file 'src/lib/OnlineAccountsDaemon/com.ubuntu.OnlineAccounts.Manager.xml' |
396 | --- src/lib/OnlineAccountsDaemon/com.ubuntu.OnlineAccounts.Manager.xml 2015-08-28 14:25:23 +0000 |
397 | +++ src/lib/OnlineAccountsDaemon/com.ubuntu.OnlineAccounts.Manager.xml 2016-11-10 09:12:06 +0000 |
398 | @@ -49,6 +49,7 @@ |
399 | --> |
400 | <method name="GetAccounts"> |
401 | <arg name="filters" type="a{sv}" direction="in" /> |
402 | + |
403 | <!-- |
404 | The return value is a list of account IDs paired with a dictionary of account data. |
405 | This will always include: |
406 | @@ -61,9 +62,22 @@ |
407 | the framework level. |
408 | --> |
409 | <arg name="accounts" type="a(ua{sv})" direction="out" /> |
410 | + |
411 | + <!-- |
412 | + The returned "services" is a list of dictionaries of the services' data. |
413 | + This will always include: |
414 | + - "serviceId" (s) |
415 | + - "displayName" (s): the translated display name |
416 | + - "iconSource" (s): URL to the service icon; if the URL starts with |
417 | + "image://theme/", then what follows is the symbolic icon name |
418 | + --> |
419 | + <arg name="services" type="aa{sv}" direction="out" /> |
420 | + |
421 | <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap"/> |
422 | <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" |
423 | value="QList<AccountInfo>"/> |
424 | + <annotation name="org.qtproject.QtDBus.QtTypeName.Out1" |
425 | + value="QList<QVariantMap>"/> |
426 | </method> |
427 | |
428 | <!-- |
429 | |
430 | === modified file 'src/lib/OnlineAccountsDaemon/dbus_constants.h' |
431 | --- src/lib/OnlineAccountsDaemon/dbus_constants.h 2016-02-11 09:00:13 +0000 |
432 | +++ src/lib/OnlineAccountsDaemon/dbus_constants.h 2016-11-10 09:12:06 +0000 |
433 | @@ -42,6 +42,9 @@ |
434 | # define ONLINE_ACCOUNTS_INFO_CHANGE_DISABLED 1 |
435 | # define ONLINE_ACCOUNTS_INFO_CHANGE_UPDATED 2 |
436 | |
437 | +/* Keys for the service info dictionary */ |
438 | +#define ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE "iconSource" |
439 | + |
440 | /* Error codes */ |
441 | #define ONLINE_ACCOUNTS_ERROR_PREFIX "com.ubuntu.OnlineAccounts.Error." |
442 | #define ONLINE_ACCOUNTS_ERROR_NO_ACCOUNT \ |
443 | |
444 | === added file 'src/lib/OnlineAccountsDaemon/i18n.cpp' |
445 | --- src/lib/OnlineAccountsDaemon/i18n.cpp 1970-01-01 00:00:00 +0000 |
446 | +++ src/lib/OnlineAccountsDaemon/i18n.cpp 2016-11-10 09:12:06 +0000 |
447 | @@ -0,0 +1,34 @@ |
448 | +/* |
449 | + * This file is part of OnlineAccountsDaemon |
450 | + * |
451 | + * Copyright (C) 2016 Canonical Ltd. |
452 | + * |
453 | + * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> |
454 | + * |
455 | + * This program is free software: you can redistribute it and/or modify it |
456 | + * under the terms of the GNU Lesser General Public License version 3, as |
457 | + * published by the Free Software Foundation. |
458 | + * |
459 | + * This program is distributed in the hope that it will be useful, but |
460 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
461 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
462 | + * PURPOSE. See the GNU Lesser General Public License for more details. |
463 | + * |
464 | + * You should have received a copy of the GNU Lesser General Public License |
465 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
466 | + */ |
467 | + |
468 | +#define NO_TR_OVERRIDE |
469 | +#include "i18n.h" |
470 | + |
471 | +#include <libintl.h> |
472 | + |
473 | +namespace OnlineAccountsDaemon { |
474 | + |
475 | +QString translate(const QString &text, const QString &domain) |
476 | +{ |
477 | + return QString::fromUtf8(dgettext(domain.toUtf8().constData(), |
478 | + text.toUtf8().constData())); |
479 | +} |
480 | + |
481 | +}; // namespace |
482 | |
483 | === added file 'src/lib/OnlineAccountsDaemon/i18n.h' |
484 | --- src/lib/OnlineAccountsDaemon/i18n.h 1970-01-01 00:00:00 +0000 |
485 | +++ src/lib/OnlineAccountsDaemon/i18n.h 2016-11-10 09:12:06 +0000 |
486 | @@ -0,0 +1,32 @@ |
487 | +/* |
488 | + * This file is part of OnlineAccountsDaemon |
489 | + * |
490 | + * Copyright (C) 2016 Canonical Ltd. |
491 | + * |
492 | + * Contact: Alberto Mardegan <alberto.mardegan@canonical.com> |
493 | + * |
494 | + * This program is free software: you can redistribute it and/or modify it |
495 | + * under the terms of the GNU Lesser General Public License version 3, as |
496 | + * published by the Free Software Foundation. |
497 | + * |
498 | + * This program is distributed in the hope that it will be useful, but |
499 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
500 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
501 | + * PURPOSE. See the GNU Lesser General Public License for more details. |
502 | + * |
503 | + * You should have received a copy of the GNU Lesser General Public License |
504 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
505 | + */ |
506 | + |
507 | +#ifndef ONLINE_ACCOUNTS_DAEMON_I18N_H |
508 | +#define ONLINE_ACCOUNTS_DAEMON_I18N_H |
509 | + |
510 | +#include <QString> |
511 | + |
512 | +namespace OnlineAccountsDaemon { |
513 | + |
514 | +QString translate(const QString &text, const QString &domain); |
515 | + |
516 | +} // namespace |
517 | + |
518 | +#endif // ONLINE_ACCOUNTS_DAEMON_I18N_H |
519 | |
520 | === modified file 'src/lib/OnlineAccountsDaemon/manager.cpp' |
521 | --- src/lib/OnlineAccountsDaemon/manager.cpp 2016-09-28 13:09:06 +0000 |
522 | +++ src/lib/OnlineAccountsDaemon/manager.cpp 2016-11-10 09:12:06 +0000 |
523 | @@ -36,6 +36,7 @@ |
524 | #include "authenticator.h" |
525 | #include "client_registry.h" |
526 | #include "dbus_constants.h" |
527 | +#include "i18n.h" |
528 | #include "manager_adaptor.h" |
529 | #include "state_saver.h" |
530 | |
531 | @@ -78,8 +79,10 @@ |
532 | const QStringList &clients); |
533 | |
534 | AccountInfo readAccountInfo(const Accounts::AccountService *as); |
535 | + QList<QVariantMap> buildServiceList(const Accounts::Application &app) const; |
536 | QList<AccountInfo> getAccounts(const QVariantMap &filters, |
537 | - const CallContext &context); |
538 | + const CallContext &context, |
539 | + QList<QVariantMap> &services); |
540 | void authenticate(uint accountId, const QString &serviceId, |
541 | bool interactive, bool invalidate, |
542 | const QVariantMap ¶meters, |
543 | @@ -89,6 +92,8 @@ |
544 | const CallContext &context); |
545 | bool canAccess(const QString &context, const QString &serviceId); |
546 | |
547 | + static QString applicationIdFromLabel(const QString &label); |
548 | + |
549 | void notifyAccountChange(const ActiveAccount &account, uint change); |
550 | |
551 | private Q_SLOTS: |
552 | @@ -344,22 +349,82 @@ |
553 | return AccountInfo(as->account()->id(), info); |
554 | } |
555 | |
556 | +QList<QVariantMap> |
557 | +ManagerPrivate::buildServiceList(const Accounts::Application &app) const |
558 | +{ |
559 | + QList<QVariantMap> services; |
560 | + |
561 | + const auto serviceList = m_manager.serviceList(app); |
562 | + for (const Accounts::Service &service: serviceList) { |
563 | + QString displayName = translate(service.displayName(), |
564 | + service.trCatalog()); |
565 | + QString icon = service.iconName(); |
566 | + |
567 | + /* Applications might declare support for a service while the provider |
568 | + * (and account plugin) for that account is not installed. We probably |
569 | + * don't want to include these services in the list, as it would lead |
570 | + * to empty/invalid UI elements. */ |
571 | + Accounts::Provider provider = m_manager.provider(service.provider()); |
572 | + if (!provider.isValid()) continue; |
573 | + |
574 | + /* Now check the service data; if either display name or icon are |
575 | + * empty, fetch this information from the provider file, as a fallback |
576 | + */ |
577 | + if (displayName.isEmpty() || |
578 | + // sometimes we use a '.' as display name placeholder |
579 | + displayName == ".") { |
580 | + displayName = translate(provider.displayName(), |
581 | + provider.trCatalog()); |
582 | + } |
583 | + if (icon.isEmpty()) { |
584 | + icon = provider.iconName(); |
585 | + } |
586 | + |
587 | + QString iconSource; |
588 | + if (icon.startsWith('/')) { |
589 | + iconSource = QStringLiteral("file:/") + icon; |
590 | + } else { |
591 | + iconSource = QStringLiteral("image://theme/") + icon; |
592 | + } |
593 | + |
594 | + services.append({ |
595 | + { ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID, service.name() }, |
596 | + { ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME, displayName }, |
597 | + { ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE, iconSource }, |
598 | + }); |
599 | + } |
600 | + |
601 | + return services; |
602 | +} |
603 | + |
604 | QList<AccountInfo> ManagerPrivate::getAccounts(const QVariantMap &filters, |
605 | - const CallContext &context) |
606 | + const CallContext &context, |
607 | + QList<QVariantMap> &services) |
608 | { |
609 | QString desiredApplicationId = filters.value("applicationId").toString(); |
610 | QString desiredServiceId = filters.value("serviceId").toString(); |
611 | Accounts::AccountId desiredAccountId = filters.value("accountId").toUInt(); |
612 | |
613 | - Accounts::Application application = desiredApplicationId.isEmpty() ? |
614 | - Accounts::Application() : m_manager.application(desiredApplicationId); |
615 | - |
616 | - if (application.isValid() && |
617 | - canAccess(context.securityContext(), desiredApplicationId)) { |
618 | + QString applicationId = desiredApplicationId.isEmpty() ? |
619 | + applicationIdFromLabel(context.securityContext()) : desiredApplicationId; |
620 | + |
621 | + Accounts::Application application = m_manager.application(applicationId); |
622 | + |
623 | + QList<AccountInfo> accounts; |
624 | + |
625 | + if (!application.isValid() || |
626 | + !canAccess(context.securityContext(), applicationId)) { |
627 | + if (!desiredApplicationId.isEmpty()) { |
628 | + context.sendError(ONLINE_ACCOUNTS_ERROR_PERMISSION_DENIED, |
629 | + QString("App '%1' cannot act as '%2'"). |
630 | + arg(applicationId).arg(desiredApplicationId)); |
631 | + return accounts; |
632 | + } |
633 | + } else { |
634 | m_clients.insert(context.clientName(), application); |
635 | } |
636 | |
637 | - QList<AccountInfo> accounts; |
638 | + services = buildServiceList(application); |
639 | |
640 | Q_FOREACH(Accounts::AccountId accountId, m_manager.accountListEnabled()) { |
641 | if (desiredAccountId != 0 && accountId != desiredAccountId) { |
642 | @@ -473,6 +538,16 @@ |
643 | return serviceId.left(pos) == pkgname; |
644 | } |
645 | |
646 | +QString ManagerPrivate::applicationIdFromLabel(const QString &label) |
647 | +{ |
648 | + QStringList parts = label.split('_'); |
649 | + if (parts.count() == 3) { |
650 | + return QStringList(parts.mid(0, 2)).join('_'); |
651 | + } else { |
652 | + return QString(); |
653 | + } |
654 | +} |
655 | + |
656 | void ManagerPrivate::onAccountServiceEnabled(bool enabled) |
657 | { |
658 | auto as = qobject_cast<Accounts::AccountService*>(sender()); |
659 | @@ -553,10 +628,11 @@ |
660 | } |
661 | |
662 | QList<AccountInfo> Manager::getAccounts(const QVariantMap &filters, |
663 | - const CallContext &context) |
664 | + const CallContext &context, |
665 | + QList<QVariantMap> &services) |
666 | { |
667 | Q_D(Manager); |
668 | - return d->getAccounts(filters, context); |
669 | + return d->getAccounts(filters, context, services); |
670 | } |
671 | |
672 | void Manager::authenticate(uint accountId, const QString &serviceId, |
673 | |
674 | === modified file 'src/lib/OnlineAccountsDaemon/manager.h' |
675 | --- src/lib/OnlineAccountsDaemon/manager.h 2015-09-03 13:28:30 +0000 |
676 | +++ src/lib/OnlineAccountsDaemon/manager.h 2016-11-10 09:12:06 +0000 |
677 | @@ -52,7 +52,8 @@ |
678 | bool isIdle() const; |
679 | |
680 | QList<AccountInfo> getAccounts(const QVariantMap &filters, |
681 | - const CallContext &context); |
682 | + const CallContext &context, |
683 | + QList<QVariantMap> &services); |
684 | void authenticate(uint accountId, const QString &serviceId, |
685 | bool interactive, bool invalidate, |
686 | const QVariantMap ¶meters, |
687 | |
688 | === modified file 'src/lib/OnlineAccountsDaemon/manager_adaptor.cpp' |
689 | --- src/lib/OnlineAccountsDaemon/manager_adaptor.cpp 2015-08-28 14:25:23 +0000 |
690 | +++ src/lib/OnlineAccountsDaemon/manager_adaptor.cpp 2016-11-10 09:12:06 +0000 |
691 | @@ -147,6 +147,7 @@ |
692 | qRegisterMetaType<QList<AccountInfo> >("QList<AccountInfo>"); |
693 | qDBusRegisterMetaType<AccountInfo>(); |
694 | qDBusRegisterMetaType<QList<AccountInfo>>(); |
695 | + qDBusRegisterMetaType<QList<QVariantMap>>(); |
696 | |
697 | setAutoRelaySignals(false); |
698 | } |
699 | @@ -175,10 +176,13 @@ |
700 | return QVariantMap(); |
701 | } |
702 | |
703 | -QList<AccountInfo> ManagerAdaptor::GetAccounts(const QVariantMap &filters) |
704 | +void ManagerAdaptor::GetAccounts(const QVariantMap &filters, |
705 | + QList<AccountInfo> &accounts, |
706 | + QList<QVariantMap> &services) |
707 | { |
708 | - return parent()->getAccounts(filters, |
709 | - CallContext(dbusContext())); |
710 | + accounts = parent()->getAccounts(filters, |
711 | + CallContext(dbusContext()), |
712 | + services); |
713 | } |
714 | |
715 | AccountInfo ManagerAdaptor::RequestAccess(const QString &serviceId, |
716 | |
717 | === modified file 'src/lib/OnlineAccountsDaemon/manager_adaptor.h' |
718 | --- src/lib/OnlineAccountsDaemon/manager_adaptor.h 2015-09-02 11:42:04 +0000 |
719 | +++ src/lib/OnlineAccountsDaemon/manager_adaptor.h 2016-11-10 09:12:06 +0000 |
720 | @@ -85,6 +85,7 @@ |
721 | " <method name=\"GetAccounts\">\n" |
722 | " <arg direction=\"in\" type=\"a{sv}\" name=\"filters\"/>\n" |
723 | " <arg direction=\"out\" type=\"a(ua{sv})\" name=\"accounts\"/>\n" |
724 | +" <arg direction=\"out\" type=\"aa{sv}\" name=\"services\"/>\n" |
725 | " </method>\n" |
726 | " <method name=\"Authenticate\">\n" |
727 | " <arg direction=\"in\" type=\"u\" name=\"accountId\"/>\n" |
728 | @@ -123,7 +124,9 @@ |
729 | QVariantMap Authenticate(uint accountId, const QString &serviceId, |
730 | bool interactive, bool invalidate, |
731 | const QVariantMap ¶meters); |
732 | - QList<AccountInfo> GetAccounts(const QVariantMap &filters); |
733 | + void GetAccounts(const QVariantMap &filters, |
734 | + QList<AccountInfo> &accounts, |
735 | + QList<QVariantMap> &services); |
736 | AccountInfo RequestAccess(const QString &serviceId, |
737 | const QVariantMap ¶meters, |
738 | QVariantMap &credentials); |
739 | |
740 | === modified file 'src/lib/Ubuntu/OnlineAccounts.2/account.cpp' |
741 | --- src/lib/Ubuntu/OnlineAccounts.2/account.cpp 2016-01-13 14:23:12 +0000 |
742 | +++ src/lib/Ubuntu/OnlineAccounts.2/account.cpp 2016-11-10 09:12:06 +0000 |
743 | @@ -26,6 +26,9 @@ |
744 | #include "OnlineAccounts/AuthenticationReply" |
745 | #include "OnlineAccounts/PendingCall" |
746 | |
747 | +#include <QDebug> |
748 | +#include <QJSEngine> |
749 | + |
750 | using namespace OnlineAccountsModule; |
751 | |
752 | namespace OnlineAccountsModule { |
753 | @@ -36,20 +39,25 @@ |
754 | Q_DECLARE_PUBLIC(Account) |
755 | |
756 | public: |
757 | - AccountPrivate(OnlineAccounts::Account *account, Account *q); |
758 | + AccountPrivate(OnlineAccounts::Account *account, QJSEngine *engine, |
759 | + Account *q); |
760 | |
761 | private Q_SLOTS: |
762 | void onAuthenticationFinished(); |
763 | |
764 | private: |
765 | OnlineAccounts::Account *m_account; |
766 | + QJSEngine *m_engine; |
767 | mutable Account *q_ptr; |
768 | }; |
769 | |
770 | } // namespace |
771 | |
772 | -AccountPrivate::AccountPrivate(OnlineAccounts::Account *account, Account *q): |
773 | +AccountPrivate::AccountPrivate(OnlineAccounts::Account *account, |
774 | + QJSEngine *engine, |
775 | + Account *q): |
776 | m_account(account), |
777 | + m_engine(engine), |
778 | q_ptr(q) |
779 | { |
780 | QObject::connect(account, SIGNAL(changed()), |
781 | @@ -122,9 +130,10 @@ |
782 | * \endlist |
783 | */ |
784 | |
785 | -Account::Account(OnlineAccounts::Account *account, QObject *parent): |
786 | +Account::Account(OnlineAccounts::Account *account, QJSEngine *engine, |
787 | + QObject *parent): |
788 | QObject(parent), |
789 | - d_ptr(new AccountPrivate(account, this)) |
790 | + d_ptr(new AccountPrivate(account, engine, this)) |
791 | { |
792 | } |
793 | |
794 | @@ -187,6 +196,27 @@ |
795 | } |
796 | |
797 | /*! |
798 | + * \qmlproperty int Account::service |
799 | + * |
800 | + * Service data associated with this account. This is an object containing the |
801 | + * following properties: |
802 | + * \list |
803 | + * \li \c serviceId - same service ID returned by Account::serviceId |
804 | + * \li \c displayName - the localized display name for the service |
805 | + * \li \c iconSource - URL for the icon; can be a "file://" URL to a local |
806 | + * file, or an icon from the theme if the URL starts with "image://theme/" |
807 | + */ |
808 | +QJSValue Account::service() const |
809 | +{ |
810 | + Q_D(const Account); |
811 | +#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) |
812 | + return d->m_engine->toScriptValue(d->m_account->service()); |
813 | +#else |
814 | + return d->m_engine->toScriptValue(d->m_account->service().toMap()); |
815 | +#endif |
816 | +} |
817 | + |
818 | +/*! |
819 | * \qmlproperty enumeration Account::authenticationMethod |
820 | * |
821 | * The authentication method used when authenticating with the account. |
822 | |
823 | === modified file 'src/lib/Ubuntu/OnlineAccounts.2/account.h' |
824 | --- src/lib/Ubuntu/OnlineAccounts.2/account.h 2016-01-13 14:23:12 +0000 |
825 | +++ src/lib/Ubuntu/OnlineAccounts.2/account.h 2016-11-10 09:12:06 +0000 |
826 | @@ -21,10 +21,13 @@ |
827 | #ifndef ONLINE_ACCOUNTS_MODULE_ACCOUNT_H |
828 | #define ONLINE_ACCOUNTS_MODULE_ACCOUNT_H |
829 | |
830 | +#include <QJSValue> |
831 | #include <QObject> |
832 | #include <QString> |
833 | #include <QVariantMap> |
834 | |
835 | +class QJSEngine; |
836 | + |
837 | namespace OnlineAccounts { |
838 | class Account; |
839 | } |
840 | @@ -40,6 +43,7 @@ |
841 | Q_PROPERTY(QString displayName READ displayName NOTIFY accountChanged) |
842 | Q_PROPERTY(int accountId READ accountId CONSTANT) |
843 | Q_PROPERTY(QString serviceId READ serviceId CONSTANT) |
844 | + Q_PROPERTY(QJSValue service READ service CONSTANT) |
845 | Q_PROPERTY(AuthenticationMethod authenticationMethod \ |
846 | READ authenticationMethod CONSTANT) |
847 | Q_PROPERTY(QVariantMap settings READ settings NOTIFY accountChanged) |
848 | @@ -64,13 +68,15 @@ |
849 | ErrorCodeInteractionRequired, |
850 | }; |
851 | |
852 | - explicit Account(OnlineAccounts::Account *account, QObject *parent = 0); |
853 | + explicit Account(OnlineAccounts::Account *account, QJSEngine *engine, |
854 | + QObject *parent = 0); |
855 | ~Account(); |
856 | |
857 | bool isValid() const; |
858 | QString displayName() const; |
859 | int accountId() const; |
860 | QString serviceId() const; |
861 | + QJSValue service() const; |
862 | AuthenticationMethod authenticationMethod() const; |
863 | QVariantMap settings() const; |
864 | |
865 | @@ -90,4 +96,7 @@ |
866 | |
867 | } // namespace |
868 | |
869 | +Q_DECLARE_METATYPE(OnlineAccountsModule::Account::AuthenticationMethod) |
870 | +Q_DECLARE_METATYPE(OnlineAccountsModule::Account::ErrorCode) |
871 | + |
872 | #endif // ONLINE_ACCOUNTS_MODULE_ACCOUNT_H |
873 | |
874 | === modified file 'src/lib/Ubuntu/OnlineAccounts.2/account_model.cpp' |
875 | --- src/lib/Ubuntu/OnlineAccounts.2/account_model.cpp 2016-01-18 12:23:07 +0000 |
876 | +++ src/lib/Ubuntu/OnlineAccounts.2/account_model.cpp 2016-11-10 09:12:06 +0000 |
877 | @@ -30,6 +30,7 @@ |
878 | #include <QDebug> |
879 | #include <QQmlEngine> |
880 | #include <QVariantMap> |
881 | +#include <QtQml> |
882 | |
883 | using namespace OnlineAccountsModule; |
884 | |
885 | @@ -85,6 +86,7 @@ |
886 | roleNames[AccountModel::AuthenticationMethodRole] = "authenticationMethod"; |
887 | roleNames[AccountModel::SettingsRole] = "settings"; |
888 | roleNames[AccountModel::AccountRole] = "account"; |
889 | + roleNames[AccountModel::ServiceRole] = "service"; |
890 | } |
891 | |
892 | void AccountModelPrivate::queueUpdate() |
893 | @@ -122,13 +124,17 @@ |
894 | |
895 | Account *AccountModelPrivate::handleAccount(OnlineAccounts::Account *account) |
896 | { |
897 | + Q_Q(AccountModel); |
898 | + |
899 | /* First, check if the account is already handled */ |
900 | Q_FOREACH(Account *a, m_accounts) { |
901 | if (account == a->internalObject()) { |
902 | return a; |
903 | } |
904 | } |
905 | - Account *a = new Account(account, this); |
906 | + |
907 | + QQmlEngine *engine = qmlEngine(q); |
908 | + Account *a = new Account(account, engine, this); |
909 | QQmlEngine::setObjectOwnership(a, QQmlEngine::CppOwnership); |
910 | QObject::connect(a, SIGNAL(validChanged()), |
911 | this, SLOT(onAccountValidChanged())); |
912 | @@ -386,6 +392,24 @@ |
913 | return objects; |
914 | } |
915 | |
916 | +QJSValue AccountModel::serviceList() const |
917 | +{ |
918 | + Q_D(const AccountModel); |
919 | + QJSEngine *engine = qmlEngine(this); |
920 | + QJSValue ret = engine->newArray(); |
921 | + if (!d->m_manager) return ret; |
922 | + int i = 0; |
923 | + Q_FOREACH(const auto &service, d->m_manager->availableServices()) { |
924 | +#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) |
925 | + QJSValue v = engine->toScriptValue(service); |
926 | +#else |
927 | + QJSValue v = engine->toScriptValue(service.toMap()); |
928 | +#endif |
929 | + ret.setProperty(i++, v); |
930 | + } |
931 | + return ret; |
932 | +} |
933 | + |
934 | /*! |
935 | * \qmlsignal AccountModel::accessReply(jsobject reply, jsobject authenticationData) |
936 | * |
937 | @@ -495,6 +519,9 @@ |
938 | case AccountRole: |
939 | ret = QVariant::fromValue<QObject*>(account); |
940 | break; |
941 | + case ServiceRole: |
942 | + ret = QVariant::fromValue(account->service()); |
943 | + break; |
944 | } |
945 | |
946 | return ret; |
947 | |
948 | === modified file 'src/lib/Ubuntu/OnlineAccounts.2/account_model.h' |
949 | --- src/lib/Ubuntu/OnlineAccounts.2/account_model.h 2016-01-18 12:23:07 +0000 |
950 | +++ src/lib/Ubuntu/OnlineAccounts.2/account_model.h 2016-11-10 09:12:06 +0000 |
951 | @@ -21,8 +21,12 @@ |
952 | #ifndef ONLINE_ACCOUNTS_MODULE_ACCOUNT_MODEL_H |
953 | #define ONLINE_ACCOUNTS_MODULE_ACCOUNT_MODEL_H |
954 | |
955 | +#include "OnlineAccounts/Service" |
956 | + |
957 | #include <QAbstractListModel> |
958 | #include <QQmlParserStatus> |
959 | +#include <QQmlListProperty> |
960 | +#include <QJSValue> |
961 | #include <QString> |
962 | #include <QVariant> |
963 | |
964 | @@ -43,6 +47,8 @@ |
965 | WRITE setServiceId NOTIFY serviceIdChanged) |
966 | Q_PROPERTY(QList<QObject*> accountList READ accountList \ |
967 | NOTIFY accountListChanged) |
968 | + Q_PROPERTY(QJSValue serviceList READ serviceList \ |
969 | + NOTIFY isReadyChanged) |
970 | |
971 | public: |
972 | enum Roles { |
973 | @@ -53,6 +59,7 @@ |
974 | AuthenticationMethodRole, |
975 | SettingsRole, |
976 | AccountRole, |
977 | + ServiceRole, |
978 | }; |
979 | |
980 | explicit AccountModel(QObject *parent = 0); |
981 | @@ -68,6 +75,8 @@ |
982 | |
983 | QList<QObject*> accountList() const; |
984 | |
985 | + QJSValue serviceList() const; |
986 | + |
987 | Q_INVOKABLE void requestAccess(const QString &service, |
988 | const QVariantMap ¶ms); |
989 | |
990 | |
991 | === modified file 'src/lib/Ubuntu/OnlineAccounts.2/plugin.cpp' |
992 | --- src/lib/Ubuntu/OnlineAccounts.2/plugin.cpp 2015-07-31 12:44:30 +0000 |
993 | +++ src/lib/Ubuntu/OnlineAccounts.2/plugin.cpp 2016-11-10 09:12:06 +0000 |
994 | @@ -20,6 +20,7 @@ |
995 | |
996 | #include "plugin.h" |
997 | |
998 | +#include "account.h" |
999 | #include "account_model.h" |
1000 | |
1001 | #include <QDebug> |
1002 | @@ -32,4 +33,8 @@ |
1003 | qDebug() << Q_FUNC_INFO << uri; |
1004 | |
1005 | qmlRegisterType<AccountModel>(uri, 2, 0, "AccountModel"); |
1006 | + qmlRegisterUncreatableType<Account>(uri, 2, 0, "Account", |
1007 | + "Cannot be created from QML"); |
1008 | + qmlRegisterUncreatableType<OnlineAccounts::Service>(uri, 2, 0, "Service", |
1009 | + "Cannot be created from QML"); |
1010 | } |
1011 | |
1012 | === modified file 'tests/daemon/functional_tests/data/com.ubuntu.tests_application.application' |
1013 | --- tests/daemon/functional_tests/data/com.ubuntu.tests_application.application 2015-07-07 12:58:49 +0000 |
1014 | +++ tests/daemon/functional_tests/data/com.ubuntu.tests_application.application 2016-11-10 09:12:06 +0000 |
1015 | @@ -5,9 +5,12 @@ |
1016 | <desktop-entry>mailer.desktop</desktop-entry> |
1017 | |
1018 | <services> |
1019 | - <service id="coolshare"> |
1020 | + <service id="com.ubuntu.tests_coolshare"> |
1021 | <description>Mailer can even share stuff on CoolShare</description> |
1022 | </service> |
1023 | + <service id="missing-provider"> |
1024 | + <description>service exists, provider does not</description> |
1025 | + </service> |
1026 | </services> |
1027 | <profile>com.ubuntu.tests_application_0.3</profile> |
1028 | </application> |
1029 | |
1030 | === modified file 'tests/daemon/functional_tests/data/com.ubuntu.tests_coolshare.service' |
1031 | --- tests/daemon/functional_tests/data/com.ubuntu.tests_coolshare.service 2016-09-28 13:09:06 +0000 |
1032 | +++ tests/daemon/functional_tests/data/com.ubuntu.tests_coolshare.service 2016-11-10 09:12:06 +0000 |
1033 | @@ -1,5 +1,5 @@ |
1034 | <?xml version="1.0" encoding="UTF-8" ?> |
1035 | -<service id="coolshare"> |
1036 | +<service id="com.ubuntu.tests_coolshare"> |
1037 | <type>sharing</type> |
1038 | <name>Cool Share</name> |
1039 | <icon>general_otherservice</icon> |
1040 | |
1041 | === modified file 'tests/daemon/functional_tests/data/coolmail.service' |
1042 | --- tests/daemon/functional_tests/data/coolmail.service 2015-07-02 08:29:48 +0000 |
1043 | +++ tests/daemon/functional_tests/data/coolmail.service 2016-11-10 09:12:06 +0000 |
1044 | @@ -2,7 +2,6 @@ |
1045 | <service id="coolmail"> |
1046 | <type>e-mail</type> |
1047 | <name>Cool Mail</name> |
1048 | - <icon>general_myservice</icon> |
1049 | <provider>cool</provider> |
1050 | |
1051 | <template> |
1052 | |
1053 | === added file 'tests/daemon/functional_tests/data/missing-provider.service' |
1054 | --- tests/daemon/functional_tests/data/missing-provider.service 1970-01-01 00:00:00 +0000 |
1055 | +++ tests/daemon/functional_tests/data/missing-provider.service 2016-11-10 09:12:06 +0000 |
1056 | @@ -0,0 +1,14 @@ |
1057 | +<?xml version="1.0" encoding="UTF-8" ?> |
1058 | +<service id="missing-provider"> |
1059 | + <type>sharing</type> |
1060 | + <name>Orphan</name> |
1061 | + <icon>icon_missing_provider</icon> |
1062 | + <provider>missing</provider> |
1063 | + |
1064 | + <template> |
1065 | + <group name="auth"> |
1066 | + <setting name="method">password</setting> |
1067 | + <setting name="mechanism">password</setting> |
1068 | + </group> |
1069 | + </template> |
1070 | +</service> |
1071 | |
1072 | === modified file 'tests/daemon/functional_tests/functional_tests.cpp' |
1073 | --- tests/daemon/functional_tests/functional_tests.cpp 2016-10-13 13:42:12 +0000 |
1074 | +++ tests/daemon/functional_tests/functional_tests.cpp 2016-11-10 09:12:06 +0000 |
1075 | @@ -60,8 +60,28 @@ |
1076 | return qstrdup(doc.toJson(QJsonDocument::Compact).data()); |
1077 | } |
1078 | |
1079 | +template<> |
1080 | +char *toString(const QSet<QVariantMap> &set) |
1081 | +{ |
1082 | + QByteArray ba = "QSet<QVariantMap>("; |
1083 | + QStringList list; |
1084 | + Q_FOREACH(const QVariantMap &map, set) { |
1085 | + list.append(QJsonDocument::fromVariant(map).toJson(QJsonDocument::Compact)); |
1086 | + } |
1087 | + ba += list.join(", "); |
1088 | + ba += ")"; |
1089 | + return qstrdup(ba.data()); |
1090 | +} |
1091 | + |
1092 | } // QTest namespace |
1093 | |
1094 | +static inline uint qHash(const QVariantMap &m, uint seed = 0) |
1095 | +{ |
1096 | + QString signature = QStringList(m.keys()).join(' ') + |
1097 | + m.value(ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID).toString(); |
1098 | + return ::qHash(signature, seed); |
1099 | +} |
1100 | + |
1101 | class TestProcess: public QProcess |
1102 | { |
1103 | Q_OBJECT |
1104 | @@ -90,6 +110,12 @@ |
1105 | void quit() { write("\n"); waitForFinished(); } |
1106 | |
1107 | QList<AccountInfo> getAccounts(const QVariantMap &filters) { |
1108 | + QList<QVariantMap> services; |
1109 | + return getAccounts(filters, services); |
1110 | + } |
1111 | + |
1112 | + QList<AccountInfo> getAccounts(const QVariantMap &filters, |
1113 | + QList<QVariantMap> &services) { |
1114 | QJsonDocument doc(QJsonObject::fromVariantMap(filters)); |
1115 | m_replyExpected = true; |
1116 | write("GetAccounts -f "); |
1117 | @@ -97,16 +123,31 @@ |
1118 | |
1119 | waitForReadyRead(); |
1120 | doc = QJsonDocument::fromJson(readLine()); |
1121 | + qDebug() << "Got Json:" << doc; |
1122 | m_replyExpected = false; |
1123 | QList<AccountInfo> accountInfos; |
1124 | - Q_FOREACH(const QJsonValue &v, doc.array()) { |
1125 | + if (checkError(doc)) return accountInfos; |
1126 | + const QJsonArray accountsJson = doc.array().at(0).toArray(); |
1127 | + const QJsonArray servicesJson = doc.array().at(1).toArray(); |
1128 | + Q_FOREACH(const QJsonValue &v, accountsJson) { |
1129 | QJsonArray a = v.toArray(); |
1130 | accountInfos.append(AccountInfo(a.at(0).toInt(), |
1131 | a.at(1).toObject().toVariantMap())); |
1132 | } |
1133 | + Q_FOREACH(const QJsonValue &v, servicesJson) { |
1134 | + services.append(v.toObject().toVariantMap()); |
1135 | + } |
1136 | return accountInfos; |
1137 | } |
1138 | |
1139 | + QString errorName() const { return m_errorName; } |
1140 | + |
1141 | +protected: |
1142 | + bool checkError(const QJsonDocument &doc) { |
1143 | + m_errorName = doc.object().value("error").toString(); |
1144 | + return !m_errorName.isEmpty(); |
1145 | + } |
1146 | + |
1147 | private Q_SLOTS: |
1148 | void onReadyRead() { |
1149 | if (m_replyExpected) return; |
1150 | @@ -128,6 +169,7 @@ |
1151 | |
1152 | private: |
1153 | QString m_uniqueName; |
1154 | + QString m_errorName; |
1155 | bool m_replyExpected; |
1156 | }; |
1157 | |
1158 | @@ -275,35 +317,113 @@ |
1159 | delete m_dbus; |
1160 | } |
1161 | |
1162 | + |
1163 | void FunctionalTests::testGetAccountsFiltering_data() |
1164 | { |
1165 | QTest::addColumn<QVariantMap>("filters"); |
1166 | QTest::addColumn<QString>("securityContext"); |
1167 | + QTest::addColumn<QString>("expectedError"); |
1168 | QTest::addColumn<QList<int> >("expectedAccountIds"); |
1169 | + QTest::addColumn<QList<QVariantMap> >("expectedServices"); |
1170 | |
1171 | QVariantMap filters; |
1172 | QTest::newRow("empty filters") << |
1173 | filters << |
1174 | "unconfined" << |
1175 | - (QList<int>() << 1 << 2 << 3); |
1176 | + QString() << |
1177 | + (QList<int>() << 1 << 2 << 3) << |
1178 | + QList<QVariantMap> {}; |
1179 | |
1180 | QTest::newRow("empty filters, confined") << |
1181 | filters << |
1182 | "com.ubuntu.tests_application_0.2" << |
1183 | - (QList<int>() << 2); |
1184 | - |
1185 | - filters[ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID] = "coolmail"; |
1186 | - QTest::newRow("by service ID") << |
1187 | - filters << |
1188 | - "unconfined" << |
1189 | - (QList<int>() << 1 << 3); |
1190 | + QString() << |
1191 | + (QList<int>() << 2) << |
1192 | + QList<QVariantMap> { |
1193 | + { |
1194 | + { ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME, "Cool Share" }, |
1195 | + { ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID, "com.ubuntu.tests_coolshare" }, |
1196 | + { ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE, "image://theme/general_otherservice" }, |
1197 | + }, |
1198 | + }; |
1199 | + |
1200 | + filters[ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID] = "coolmail"; |
1201 | + QTest::newRow("unconfined, by service ID") << |
1202 | + filters << |
1203 | + "unconfined" << |
1204 | + QString() << |
1205 | + (QList<int>() << 1 << 3) << |
1206 | + QList<QVariantMap> {}; |
1207 | + filters.clear(); |
1208 | + |
1209 | + filters[ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID] = "coolmail"; |
1210 | + QTest::newRow("confined, by service ID") << |
1211 | + filters << |
1212 | + "com.ubuntu.tests_application_0.2" << |
1213 | + QString() << |
1214 | + (QList<int>()) << |
1215 | + QList<QVariantMap> { |
1216 | + { |
1217 | + { ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME, "Cool Share" }, |
1218 | + { ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID, "com.ubuntu.tests_coolshare" }, |
1219 | + { ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE, "image://theme/general_otherservice" }, |
1220 | + }, |
1221 | + }; |
1222 | + filters.clear(); |
1223 | + |
1224 | + filters["applicationId"] = "com.ubuntu.tests_application"; |
1225 | + QTest::newRow("by app ID") << |
1226 | + filters << |
1227 | + "unconfined" << |
1228 | + QString() << |
1229 | + (QList<int>() << 2) << |
1230 | + QList<QVariantMap> { |
1231 | + { |
1232 | + { ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME, "Cool Share" }, |
1233 | + { ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID, "com.ubuntu.tests_coolshare" }, |
1234 | + { ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE, "image://theme/general_otherservice" }, |
1235 | + }, |
1236 | + }; |
1237 | + filters.clear(); |
1238 | + |
1239 | + filters["applicationId"] = "mailer"; |
1240 | + QTest::newRow("confined app requesting other app ID") << |
1241 | + filters << |
1242 | + "com.ubuntu.tests_application_0.2" << |
1243 | + ONLINE_ACCOUNTS_ERROR_PERMISSION_DENIED << |
1244 | + (QList<int>()) << |
1245 | + QList<QVariantMap> {}; |
1246 | + filters.clear(); |
1247 | + |
1248 | + filters["applicationId"] = "mailer"; |
1249 | + QTest::newRow("by app ID, with service fallback") << |
1250 | + filters << |
1251 | + "unconfined" << |
1252 | + QString() << |
1253 | + QList<int>{ 3, 1 } << |
1254 | + QList<QVariantMap> { |
1255 | + { |
1256 | + { ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME, "OAuth 1 test" }, |
1257 | + { ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID, "oauth1auth" }, |
1258 | + { ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE, "image://theme/general_myservice" }, |
1259 | + }, |
1260 | + { |
1261 | + { ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME, "Cool Mail" }, |
1262 | + { ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID, "coolmail" }, |
1263 | + { ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE, "image://theme/general_myprovider" }, |
1264 | + }, |
1265 | + }; |
1266 | + filters.clear(); |
1267 | + |
1268 | } |
1269 | |
1270 | void FunctionalTests::testGetAccountsFiltering() |
1271 | { |
1272 | QFETCH(QVariantMap, filters); |
1273 | QFETCH(QString, securityContext); |
1274 | + QFETCH(QString, expectedError); |
1275 | QFETCH(QList<int>, expectedAccountIds); |
1276 | + QFETCH(QList<QVariantMap>, expectedServices); |
1277 | |
1278 | DaemonInterface *daemon = new DaemonInterface(m_dbus->sessionConnection()); |
1279 | |
1280 | @@ -313,7 +433,10 @@ |
1281 | }; |
1282 | m_dbus->dbusApparmor().setCredentials(testProcess.uniqueName(), credentials); |
1283 | |
1284 | - QList<AccountInfo> accountInfos = testProcess.getAccounts(filters); |
1285 | + QList<QVariantMap> services; |
1286 | + QList<AccountInfo> accountInfos = testProcess.getAccounts(filters, services); |
1287 | + QCOMPARE(testProcess.errorName(), expectedError); |
1288 | + QCOMPARE(services.toSet(), expectedServices.toSet()); |
1289 | QList<int> accountIds; |
1290 | Q_FOREACH(const AccountInfo &info, accountInfos) { |
1291 | accountIds.append(info.id() + m_firstAccountId); |
1292 | |
1293 | === modified file 'tests/daemon/functional_tests/test_process.py' |
1294 | --- tests/daemon/functional_tests/test_process.py 2016-07-19 11:55:45 +0000 |
1295 | +++ tests/daemon/functional_tests/test_process.py 2016-11-10 09:12:06 +0000 |
1296 | @@ -30,8 +30,11 @@ |
1297 | filters = dbus.Dictionary(signature='sv') |
1298 | if args.filters: |
1299 | filters.update(json.loads(args.filters)) |
1300 | - print('%s' % json.dumps(self.manager.GetAccounts(filters), sort_keys=True), |
1301 | - flush=True) |
1302 | + try: |
1303 | + print('%s' % json.dumps(self.manager.GetAccounts(filters), sort_keys=True), |
1304 | + flush=True) |
1305 | + except dbus.exceptions.DBusException as err: |
1306 | + print('{ "error": "%s" }' % err.get_dbus_name(), flush=True) |
1307 | |
1308 | def on_account_changed(self, serviceId, accountInfo): |
1309 | info = json.dumps(accountInfo, sort_keys=True) |
1310 | |
1311 | === modified file 'tests/lib/OnlineAccounts/functional_tests/functional_tests.cpp' |
1312 | --- tests/lib/OnlineAccounts/functional_tests/functional_tests.cpp 2016-07-22 05:08:06 +0000 |
1313 | +++ tests/lib/OnlineAccounts/functional_tests/functional_tests.cpp 2016-11-10 09:12:06 +0000 |
1314 | @@ -26,18 +26,22 @@ |
1315 | #include "OnlineAccounts/account_info.h" |
1316 | #include "OnlineAccountsDaemon/dbus_constants.h" |
1317 | #include <QDBusConnection> |
1318 | +#include <QJsonDocument> |
1319 | +#include <QJsonObject> |
1320 | #include <QObject> |
1321 | #include <QSignalSpy> |
1322 | #include <QTest> |
1323 | #include <libqtdbusmock/DBusMock.h> |
1324 | |
1325 | namespace QTest { |
1326 | + |
1327 | template<> |
1328 | char *toString(const QVariantMap &map) |
1329 | { |
1330 | QJsonDocument doc(QJsonObject::fromVariantMap(map)); |
1331 | return qstrdup(doc.toJson(QJsonDocument::Compact).data()); |
1332 | } |
1333 | + |
1334 | } // QTest namespace |
1335 | |
1336 | class FunctionalTests: public QObject |
1337 | @@ -82,6 +86,8 @@ |
1338 | void testManagerReady(); |
1339 | void testManagerAvailableAccounts_data(); |
1340 | void testManagerAvailableAccounts(); |
1341 | + void testManagerAvailableServices_data(); |
1342 | + void testManagerAvailableServices(); |
1343 | void testManagerAccount(); |
1344 | void testManagerRequestAccess_data(); |
1345 | void testManagerRequestAccess(); |
1346 | @@ -132,7 +138,7 @@ |
1347 | QFETCH(bool, haveGetAccountsMethod); |
1348 | |
1349 | if (haveGetAccountsMethod) { |
1350 | - addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = []"); |
1351 | + addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", "ret = ([], [])"); |
1352 | } |
1353 | OnlineAccounts::Manager manager("my-app"); |
1354 | |
1355 | @@ -150,12 +156,12 @@ |
1356 | QTest::addColumn<QStringList>("expectedDisplayNames"); |
1357 | |
1358 | QTest::newRow("no accounts") << |
1359 | - "ret = []" << |
1360 | + "ret = ([], [])" << |
1361 | QList<int>() << |
1362 | QStringList(); |
1363 | |
1364 | QTest::newRow("one account, no data") << |
1365 | - "ret = [(1, {'displayName': 'Tom'})]" << |
1366 | + "ret = ([(1, {'displayName': 'Tom'})], [])" << |
1367 | (QList<int>() << 1) << |
1368 | (QStringList() << "Tom"); |
1369 | } |
1370 | @@ -166,7 +172,7 @@ |
1371 | QFETCH(QList<int>, expectedIds); |
1372 | QFETCH(QStringList, expectedDisplayNames); |
1373 | |
1374 | - addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", reply); |
1375 | + addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", reply); |
1376 | OnlineAccounts::Manager manager("my-app"); |
1377 | |
1378 | manager.waitForReady(); |
1379 | @@ -181,10 +187,77 @@ |
1380 | QCOMPARE(displayNames, expectedDisplayNames); |
1381 | } |
1382 | |
1383 | +void FunctionalTests::testManagerAvailableServices_data() |
1384 | +{ |
1385 | + QTest::addColumn<QString>("reply"); |
1386 | + QTest::addColumn<QList<QVariantMap>>("expectedServices"); |
1387 | + |
1388 | + QTest::newRow("no services") << |
1389 | + "ret = ([], [])" << |
1390 | + QList<QVariantMap> {}; |
1391 | + |
1392 | + QTest::newRow("one service") << |
1393 | + "ret = ([], [{" |
1394 | + "'" ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID "': 'app_coolshare'," |
1395 | + "'" ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME "': 'Cool Share'," |
1396 | + "'" ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE "': 'image://theme/coolshare'," |
1397 | + "}])" << |
1398 | + QList<QVariantMap> { |
1399 | + { |
1400 | + { "serviceId", "app_coolshare" }, |
1401 | + { "displayName", "Cool Share" }, |
1402 | + { "iconSource", "image://theme/coolshare"}, |
1403 | + }, |
1404 | + }; |
1405 | +} |
1406 | + |
1407 | +void FunctionalTests::testManagerAvailableServices() |
1408 | +{ |
1409 | + QFETCH(QString, reply); |
1410 | + QFETCH(QList<QVariantMap>, expectedServices); |
1411 | + |
1412 | + addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", reply); |
1413 | + OnlineAccounts::Manager manager("my-app"); |
1414 | + |
1415 | + manager.waitForReady(); |
1416 | + const auto availableServices = manager.availableServices(); |
1417 | +#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) |
1418 | + QList<QVariantMap> services; |
1419 | + for (const OnlineAccounts::Service &service: availableServices) { |
1420 | + QVariantMap data; |
1421 | + |
1422 | + const QMetaObject &mo = service.staticMetaObject; |
1423 | + for (int i = mo.propertyOffset(); i < mo.propertyCount(); i++) { |
1424 | + const QMetaProperty prop = mo.property(i); |
1425 | + data.insert(prop.name(), prop.readOnGadget(&service)); |
1426 | + } |
1427 | + |
1428 | + services.append(data); |
1429 | + } |
1430 | + |
1431 | + QCOMPARE(services, expectedServices); |
1432 | +#else |
1433 | + QCOMPARE(availableServices.count(), expectedServices.count()); |
1434 | +#endif |
1435 | +} |
1436 | + |
1437 | void FunctionalTests::testManagerAccount() |
1438 | { |
1439 | - addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", |
1440 | - "ret = [(1, {'displayName': 'John'})]"); |
1441 | + addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", |
1442 | + "ret = ([" |
1443 | + " (1, {" |
1444 | + " 'displayName': 'John'," |
1445 | + " 'serviceId': 'app_coolshare'," |
1446 | + " })," |
1447 | + " (2, {" |
1448 | + " 'displayName': 'Bob'," |
1449 | + " 'serviceId': 'a missing one'," |
1450 | + " })," |
1451 | + "], [{" |
1452 | + " 'serviceId': 'app_coolshare'," |
1453 | + " 'displayName': 'Cool Share'," |
1454 | + " 'iconSource': 'image://theme/coolshare'," |
1455 | + "}])"); |
1456 | OnlineAccounts::Manager manager("my-app"); |
1457 | |
1458 | manager.waitForReady(); |
1459 | @@ -193,10 +266,22 @@ |
1460 | OnlineAccounts::Account *account = manager.account(4); |
1461 | QVERIFY(!account); |
1462 | |
1463 | + // valid account linking to invalid service |
1464 | + account = manager.account(2); |
1465 | + QVERIFY(account); |
1466 | + QCOMPARE(account->displayName(), QString("Bob")); |
1467 | + QCOMPARE(account->serviceId(), QString("a missing one")); |
1468 | + QVERIFY(!account->service().isValid()); |
1469 | + |
1470 | // valid account |
1471 | account = manager.account(1); |
1472 | QVERIFY(account); |
1473 | QCOMPARE(account->displayName(), QString("John")); |
1474 | + QCOMPARE(account->serviceId(), QString("app_coolshare")); |
1475 | + QVERIFY(account->service().isValid()); |
1476 | + QCOMPARE(account->service().displayName(), QString("Cool Share")); |
1477 | + QCOMPARE(account->service().iconSource(), |
1478 | + QUrl("image://theme/coolshare")); |
1479 | } |
1480 | |
1481 | void FunctionalTests::testManagerRequestAccess_data() |
1482 | @@ -236,7 +321,7 @@ |
1483 | QFETCH(QString, displayName); |
1484 | QFETCH(QString, accessToken); |
1485 | |
1486 | - addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = []"); |
1487 | + addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", "ret = ([], [])"); |
1488 | addMockedMethod("RequestAccess", "sa{sv}", "(ua{sv})a{sv}", reply); |
1489 | OnlineAccounts::Manager manager("my-app"); |
1490 | |
1491 | @@ -277,12 +362,12 @@ |
1492 | QTest::addColumn<QVariantMap>("settings"); |
1493 | |
1494 | QTest::newRow("empty account") << |
1495 | - "ret = [(1, {})]" << |
1496 | + "[(1, {})]" << |
1497 | 1 << |
1498 | "" << "" << 0 << QVariantMap(); |
1499 | |
1500 | QTest::newRow("no settings") << |
1501 | - "ret = [(3, {" |
1502 | + "[(3, {" |
1503 | " 'displayName': 'Bob'," |
1504 | " 'serviceId': 'MyService'," |
1505 | " 'authMethod': 1," |
1506 | @@ -297,7 +382,7 @@ |
1507 | settings.insert("Host", "example.com"); |
1508 | settings.insert("Port", int(7000)); |
1509 | QTest::newRow("with settings") << |
1510 | - "ret = [(4, {" |
1511 | + "[(4, {" |
1512 | " 'displayName': 'Tom'," |
1513 | " 'serviceId': 'MyService'," |
1514 | " 'authMethod': 2," |
1515 | @@ -320,7 +405,8 @@ |
1516 | QFETCH(int, authenticationMethod); |
1517 | QFETCH(QVariantMap, settings); |
1518 | |
1519 | - addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", reply); |
1520 | + addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", |
1521 | + QString("ret = (%1, [])").arg(reply)); |
1522 | OnlineAccounts::Manager manager("my-app"); |
1523 | |
1524 | manager.waitForReady(); |
1525 | @@ -347,7 +433,7 @@ |
1526 | |
1527 | void FunctionalTests::testPendingCallWatcher() |
1528 | { |
1529 | - addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = []"); |
1530 | + addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", "ret = ([], [])"); |
1531 | addMockedMethod("RequestAccess", "sa{sv}", "(ua{sv})a{sv}", |
1532 | "ret = ((1, {'displayName': 'Bob'}),{})"); |
1533 | OnlineAccounts::Manager manager("my-app"); |
1534 | @@ -378,7 +464,7 @@ |
1535 | |
1536 | void FunctionalTests::testAccountChanges() |
1537 | { |
1538 | - addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = []"); |
1539 | + addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", "ret = ([], [])"); |
1540 | OnlineAccounts::Manager manager("my-app"); |
1541 | QSignalSpy accountAvailable(&manager, |
1542 | SIGNAL(accountAvailable(OnlineAccounts::Account*))); |
1543 | @@ -442,8 +528,8 @@ |
1544 | |
1545 | void FunctionalTests::testMultipleServices() |
1546 | { |
1547 | - addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", |
1548 | - "ret = [" |
1549 | + addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", |
1550 | + "ret = ([" |
1551 | "(1, {" |
1552 | " 'displayName': 'One'," |
1553 | " 'serviceId': 'service2'," |
1554 | @@ -464,7 +550,7 @@ |
1555 | " 'serviceId': 'service1'," |
1556 | " 'authMethod': 1," |
1557 | "})," |
1558 | - "]"); |
1559 | + "], [])"); |
1560 | OnlineAccounts::Manager manager("my-app"); |
1561 | manager.waitForReady(); |
1562 | |
1563 | @@ -494,8 +580,8 @@ |
1564 | |
1565 | void FunctionalTests::testAuthentication() |
1566 | { |
1567 | - addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", |
1568 | - "ret = [" |
1569 | + addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", |
1570 | + "ret = ([" |
1571 | "(1, {" |
1572 | " 'displayName': 'Bob'," |
1573 | " 'serviceId': 'MyService0'," |
1574 | @@ -516,7 +602,7 @@ |
1575 | " 'serviceId': 'MyService3'," |
1576 | " 'authMethod': 4," |
1577 | "})," |
1578 | - "]"); |
1579 | + "], [])"); |
1580 | addMockedMethod("Authenticate", "usbba{sv}", "a{sv}", |
1581 | "if args[0] == 1:\n" |
1582 | " ret = {" |
1583 | @@ -671,12 +757,12 @@ |
1584 | QFETCH(int, errorCode); |
1585 | QFETCH(QString, errorMessage); |
1586 | |
1587 | - addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", |
1588 | - "ret = [(1, {" |
1589 | + addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", |
1590 | + "ret = ([(1, {" |
1591 | " 'displayName': 'Bob'," |
1592 | " 'serviceId': 'MyService0'," |
1593 | " 'authMethod': 2," |
1594 | - "})]"); |
1595 | + "})], [])"); |
1596 | addMockedMethod("Authenticate", "usbba{sv}", "a{sv}", reply); |
1597 | OnlineAccounts::Manager manager("my-app"); |
1598 | manager.waitForReady(); |
1599 | |
1600 | === modified file 'tests/lib/qml_module/tst_qml_module.cpp' |
1601 | --- tests/lib/qml_module/tst_qml_module.cpp 2016-10-06 08:20:10 +0000 |
1602 | +++ tests/lib/qml_module/tst_qml_module.cpp 2016-11-10 09:12:06 +0000 |
1603 | @@ -55,14 +55,18 @@ |
1604 | } |
1605 | |
1606 | void addMockedMethod(const QString &name, |
1607 | - const QString &in_sig, |
1608 | - const QString &out_sig, |
1609 | - const QString &code) |
1610 | + const QString &in_sig, |
1611 | + const QString &out_sig, |
1612 | + const QString &code) |
1613 | { |
1614 | return mocked().AddMethod(ONLINE_ACCOUNTS_MANAGER_INTERFACE, |
1615 | name, in_sig, out_sig, code).waitForFinished(); |
1616 | } |
1617 | |
1618 | + void addGetAccountsMethod(const QString &code) { |
1619 | + addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})aa{sv}", code); |
1620 | + } |
1621 | + |
1622 | void emitAccountChanged(const QString &service, |
1623 | uint accountId, |
1624 | const QVariantMap &changes) |
1625 | @@ -90,6 +94,8 @@ |
1626 | void initTestCase(); |
1627 | void testModuleImport(); |
1628 | void testModelProperties(); |
1629 | + void testServices_data(); |
1630 | + void testServices(); |
1631 | void testModelRoles_data(); |
1632 | void testModelRoles(); |
1633 | void testModelFilters_data(); |
1634 | @@ -156,9 +162,85 @@ |
1635 | delete object; |
1636 | } |
1637 | |
1638 | +void ModuleTest::testServices_data() |
1639 | +{ |
1640 | + QTest::addColumn<QString>("reply"); |
1641 | + QTest::addColumn<QList<QVariantMap>>("expectedServices"); |
1642 | + |
1643 | + QTest::newRow("no services") << |
1644 | + "[]" << |
1645 | + QList<QVariantMap> {}; |
1646 | + |
1647 | + QTest::newRow("one service") << |
1648 | + "[{" |
1649 | + "'" ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID "': 'app_coolshare'," |
1650 | + "'" ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME "': 'Cool Share'," |
1651 | + "'" ONLINE_ACCOUNTS_INFO_KEY_ICON_SOURCE "': 'image://theme/coolshare'," |
1652 | + "}]" << |
1653 | + QList<QVariantMap> { |
1654 | + { |
1655 | + { "serviceId", "app_coolshare" }, |
1656 | + { "displayName", "Cool Share" }, |
1657 | + { "iconSource", "image://theme/coolshare"}, |
1658 | + }, |
1659 | + }; |
1660 | +} |
1661 | + |
1662 | +void ModuleTest::testServices() |
1663 | +{ |
1664 | + QFETCH(QString, reply); |
1665 | + QFETCH(QList<QVariantMap>, expectedServices); |
1666 | + |
1667 | + addGetAccountsMethod(QString("ret = ([], %1)").arg(reply)); |
1668 | + |
1669 | + QQmlEngine engine; |
1670 | + QQmlComponent component(&engine); |
1671 | + /* We could return the serviceList property directly, but that would be |
1672 | + * passing a OnlineAccounts::Service as QJSValue, which might not be a |
1673 | + * proof that every property is properly accessible from QML. Therefore, we |
1674 | + * explicitly run through the list and copy it as a new object. */ |
1675 | + component.setData("import Ubuntu.OnlineAccounts 2.0\n" |
1676 | + "AccountModel {\n" |
1677 | + " applicationId: \"foo\"\n" |
1678 | + " function getServices() {\n" |
1679 | + " var ret = [];\n" |
1680 | + " for (var i = 0; i < serviceList.length; i++) {\n" |
1681 | + " var s = serviceList[i];\n" |
1682 | + " var service = {};\n" |
1683 | + " for (var key in s) { service[key] = s[key]; }\n" |
1684 | + " ret.push(service);\n" |
1685 | + " }\n" |
1686 | + " return ret;\n" |
1687 | + " }\n" |
1688 | + "}", |
1689 | + QUrl()); |
1690 | + QObject *object = component.create(); |
1691 | + QVERIFY(object != 0); |
1692 | + QAbstractListModel *model = qobject_cast<QAbstractListModel*>(object); |
1693 | + QVERIFY(model != 0); |
1694 | + |
1695 | + QSignalSpy ready(object, SIGNAL(isReadyChanged())); |
1696 | + ready.wait(); |
1697 | + |
1698 | + QVariant serviceList; |
1699 | + bool ok = QMetaObject::invokeMethod(object, "getServices", |
1700 | + Q_RETURN_ARG(QVariant, serviceList)); |
1701 | + QVERIFY(ok); |
1702 | + |
1703 | + QVariantList serviceVariantList = serviceList.toList(); |
1704 | + QList<QVariantMap> services; |
1705 | + for (const QVariant &v: serviceVariantList) { |
1706 | + services.append(v.toMap()); |
1707 | + } |
1708 | + |
1709 | + QCOMPARE(services, expectedServices); |
1710 | + delete object; |
1711 | +} |
1712 | + |
1713 | void ModuleTest::testModelRoles_data() |
1714 | { |
1715 | QTest::addColumn<QString>("accountData"); |
1716 | + QTest::addColumn<QString>("serviceData"); |
1717 | QTest::addColumn<QString>("displayName"); |
1718 | QTest::addColumn<QString>("serviceId"); |
1719 | QTest::addColumn<int>("authenticationMethod"); |
1720 | @@ -167,6 +249,7 @@ |
1721 | QVariantMap settings; |
1722 | QTest::newRow("empty") << |
1723 | "{}" << |
1724 | + "" << |
1725 | "" << "" << 0 << settings; |
1726 | |
1727 | settings.insert("Server", "www.example.com"); |
1728 | @@ -179,19 +262,23 @@ |
1729 | " '" ONLINE_ACCOUNTS_INFO_KEY_SETTINGS "Server': 'www.example.com'," |
1730 | " '" ONLINE_ACCOUNTS_INFO_KEY_SETTINGS "Port': 9900," |
1731 | "}" << |
1732 | + "{" |
1733 | + " '" ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID "': 'cool'," |
1734 | + "}" << |
1735 | "Tom" << "cool" << 2 << settings; |
1736 | } |
1737 | |
1738 | void ModuleTest::testModelRoles() |
1739 | { |
1740 | QFETCH(QString, accountData); |
1741 | + QFETCH(QString, serviceData); |
1742 | QFETCH(QString, displayName); |
1743 | QFETCH(QString, serviceId); |
1744 | QFETCH(int, authenticationMethod); |
1745 | QFETCH(QVariantMap, settings); |
1746 | |
1747 | - addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", |
1748 | - QString("ret = [(1, %1)]").arg(accountData)); |
1749 | + addGetAccountsMethod(QString("ret = ([(1, %1)], [%2])"). |
1750 | + arg(accountData).arg(serviceData)); |
1751 | |
1752 | QQmlEngine engine; |
1753 | QQmlComponent component(&engine); |
1754 | @@ -218,7 +305,6 @@ |
1755 | QCOMPARE(get(model, 0, "serviceId").toString(), serviceId); |
1756 | QCOMPARE(get(model, 0, "authenticationMethod").toInt(), |
1757 | authenticationMethod); |
1758 | - // until https://bugs.launchpad.net/bugs/1479768 is fixed |
1759 | QCOMPARE(get(model, 0, "settings").toMap(), settings); |
1760 | QObject *account = get(model, 0, "account").value<QObject*>(); |
1761 | QVERIFY(account != 0); |
1762 | @@ -226,6 +312,10 @@ |
1763 | QCOMPARE(account, |
1764 | model->property("accountList").value<QList<QObject*> >().first()); |
1765 | |
1766 | + QJSValue service = get(model, 0, "service").value<QJSValue>(); |
1767 | + QVERIFY(service.isObject()); |
1768 | + QCOMPARE(service.property("serviceId").toString(), serviceId); |
1769 | + |
1770 | delete object; |
1771 | } |
1772 | |
1773 | @@ -237,17 +327,17 @@ |
1774 | QTest::addColumn<QStringList>("expectedDisplayNames"); |
1775 | |
1776 | QTest::newRow("no accounts") << |
1777 | - "ret = []" << |
1778 | + "[]" << |
1779 | "" << |
1780 | QList<int>(); |
1781 | |
1782 | QTest::newRow("one account, no service filter") << |
1783 | - "ret = [(1, {'displayName': 'Tom', 'serviceId': 'Foo' })]" << |
1784 | + "[(1, {'displayName': 'Tom', 'serviceId': 'Foo' })]" << |
1785 | "" << |
1786 | (QList<int>() << 1); |
1787 | |
1788 | QTest::newRow("one account, with service filter") << |
1789 | - "ret = [(1, {'displayName': 'Tom', 'serviceId': 'Foo' })]" << |
1790 | + "[(1, {'displayName': 'Tom', 'serviceId': 'Foo' })]" << |
1791 | "serviceId: \"bar\"" << |
1792 | QList<int>(); |
1793 | } |
1794 | @@ -258,7 +348,7 @@ |
1795 | QFETCH(QString, filters); |
1796 | QFETCH(QList<int>, expectedIds); |
1797 | |
1798 | - addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", reply); |
1799 | + addGetAccountsMethod(QString("ret = (%1, [])").arg(reply)); |
1800 | |
1801 | QQmlEngine engine; |
1802 | QQmlComponent component(&engine); |
1803 | @@ -287,7 +377,7 @@ |
1804 | |
1805 | void ModuleTest::testModelChanges() |
1806 | { |
1807 | - addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", "ret = []"); |
1808 | + addGetAccountsMethod("ret = ([], [])"); |
1809 | QQmlEngine engine; |
1810 | QQmlComponent component(&engine); |
1811 | component.setData("import Ubuntu.OnlineAccounts 2.0\n" |
1812 | @@ -397,8 +487,7 @@ |
1813 | QFETCH(QVariantMap, expectedAccessReply); |
1814 | QFETCH(QVariantMap, expectedAuthenticationData); |
1815 | |
1816 | - addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", |
1817 | - "ret = [(1, {'displayName': 'Tom', 'serviceId': 'Foo' })]"); |
1818 | + addGetAccountsMethod("ret = ([(1, {'displayName': 'Tom', 'serviceId': 'Foo' })], [])"); |
1819 | addMockedMethod("RequestAccess", "sa{sv}", "(ua{sv})a{sv}", reply); |
1820 | |
1821 | QQmlEngine engine; |
1822 | @@ -536,12 +625,11 @@ |
1823 | QFETCH(QVariantMap, params); |
1824 | QFETCH(QVariantMap, expectedAuthenticationData); |
1825 | |
1826 | - addMockedMethod("GetAccounts", "a{sv}", "a(ua{sv})", |
1827 | - QString("ret = [(1, {" |
1828 | - " 'displayName': 'Bob'," |
1829 | - " 'serviceId': 'MyService0'," |
1830 | - " 'authMethod': %1," |
1831 | - "})]").arg(authMethod)); |
1832 | + addGetAccountsMethod(QString("ret = ([(1, {" |
1833 | + " 'displayName': 'Bob'," |
1834 | + " 'serviceId': 'MyService0'," |
1835 | + " 'authMethod': %1," |
1836 | + "})], [])").arg(authMethod)); |
1837 | addMockedMethod("Authenticate", "usbba{sv}", "a{sv}", reply); |
1838 | |
1839 | QQmlEngine engine; |
I may be missing something here, but (not being familiar with the code), it looks like the translated service name is not present? We need the translated name of the service too (such as "Google" or "Dropbox", or their equivalents in Arabic script, or whatever).