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

Proposed by Alberto Mardegan on 2015-01-23
Status: Merged
Merged at revision: 227
Proposed branch: lp:~mardy/ubuntu-system-settings-online-accounts/lp1373279
Merge into: lp:~online-accounts/ubuntu-system-settings-online-accounts/master
Diff against target: 580 lines (+505/-8)
8 files modified
.bzrignore (+1/-0)
system-settings-plugin/online-accounts.settings (+2/-6)
system-settings-plugin/plugin.cpp (+116/-0)
system-settings-plugin/plugin.h (+36/-0)
system-settings-plugin/system-settings-plugin.pro (+24/-1)
tests/system-settings-plugin/system-settings-plugin.pro (+32/-0)
tests/system-settings-plugin/tst_plugin.cpp (+292/-0)
tests/tests.pro (+2/-1)
To merge this branch: bzr merge lp:~mardy/ubuntu-system-settings-online-accounts/lp1373279
Reviewer Review Type Date Requested Status
Alexandre Abreu (community) 2015-01-23 Approve on 2015-02-02
Review via email: mp+247453@code.launchpad.net

Commit message

Add account data as search keywords

Description of the change

Add account data as search keywords

To post a comment you must log in.
Alexandre Abreu (abreu-alexandre) wrote :

small comment inline

review: Needs Fixing
226. By Alberto Mardegan on 2015-01-28

Avoid inserting duplicate keywords

227. By Alberto Mardegan on 2015-02-02

Added tests

228. By Alberto Mardegan on 2015-02-02

Remove unnecessary friend

Alberto Mardegan (mardy) wrote :

I fixed the code as suggested by Alex, and added some unit tests.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2014-12-11 12:51:46 +0000
3+++ .bzrignore 2015-02-02 15:22:49 +0000
4@@ -57,3 +57,4 @@
5 /tests/online-accounts-ui/tst_notification
6 /tests/online-accounts-ui/tst_signonui_request
7 /tests/plugin/tst_application_manager
8+/tests/system-settings-plugin/tst_plugin
9
10=== modified file 'system-settings-plugin/online-accounts.settings'
11--- system-settings-plugin/online-accounts.settings 2014-09-24 19:05:32 +0000
12+++ system-settings-plugin/online-accounts.settings 2015-02-02 15:22:49 +0000
13@@ -14,14 +14,10 @@
14 "access",
15 "authorize",
16 "revoke",
17- "web",
18- "facebook",
19- "twitter",
20- "flickr",
21- "google",
22- "gmail"
23+ "web"
24 ],
25 "has-dynamic-keywords": true,
26 "has-dynamic-visibility": false,
27+ "plugin": "online-accounts",
28 "page-component": "MainPage.qml"
29 }
30
31=== added file 'system-settings-plugin/plugin.cpp'
32--- system-settings-plugin/plugin.cpp 1970-01-01 00:00:00 +0000
33+++ system-settings-plugin/plugin.cpp 2015-02-02 15:22:49 +0000
34@@ -0,0 +1,116 @@
35+/*
36+ * Copyright (C) 2015 Canonical Ltd.
37+ *
38+ * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
39+ *
40+ * This program is free software: you can redistribute it and/or modify it
41+ * under the terms of the GNU General Public License version 3, as published
42+ * by the Free Software Foundation.
43+ *
44+ * This program is distributed in the hope that it will be useful, but
45+ * WITHOUT ANY WARRANTY; without even the implied warranties of
46+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
47+ * PURPOSE. See the GNU General Public License for more details.
48+ *
49+ * You should have received a copy of the GNU General Public License along
50+ * with this program. If not, see <http://www.gnu.org/licenses/>.
51+ */
52+
53+#include "plugin.h"
54+
55+#include <Accounts/Account>
56+#include <Accounts/Manager>
57+#include <Accounts/Provider>
58+#include <Accounts/Service>
59+#include <QDebug>
60+#include <QStringList>
61+#include <SystemSettings/ItemBase>
62+#include <libintl.h>
63+
64+using namespace SystemSettings;
65+
66+class Item: public ItemBase
67+{
68+ Q_OBJECT
69+
70+public:
71+ Item(const QVariantMap &staticData, QObject *parent = 0);
72+ ~Item();
73+
74+private:
75+ void computeKeywords();
76+};
77+
78+Item::Item(const QVariantMap &staticData, QObject *parent):
79+ ItemBase(staticData, parent)
80+{
81+ computeKeywords();
82+}
83+
84+Item::~Item()
85+{
86+}
87+
88+static QStringList translations(const QString &text, const QString &domain)
89+{
90+ /* Return a list of keywords based on a translatable name:
91+ * - the untranslated text (lowercase, split into words)
92+ * - the translated text (lowercase, split into words)
93+ */
94+ QStringList keys;
95+ keys = text.toLower().split(" ", QString::SkipEmptyParts);
96+ if (!domain.isEmpty()) {
97+ QByteArray baText = text.toUtf8();
98+ QByteArray baDomain = domain.toUtf8();
99+ QString translated = QString::fromUtf8(dgettext(baDomain.constData(),
100+ baText.constData()));
101+ if (translated != text) {
102+ keys.append(translated.toLower().split(" ",
103+ QString::SkipEmptyParts));
104+ }
105+ }
106+ return keys;
107+}
108+
109+void Item::computeKeywords()
110+{
111+ Accounts::Manager *manager = new Accounts::Manager;
112+
113+ QStringList keywords;
114+
115+ /* List available providers, and add their names to the search keywords */
116+ Q_FOREACH(const Accounts::Provider &provider, manager->providerList()) {
117+ keywords.append(provider.name().toLower());
118+ keywords.append(translations(provider.displayName(),
119+ provider.trCatalog()));
120+ }
121+
122+ /* Same for services */
123+ Q_FOREACH(const Accounts::Service &service, manager->serviceList()) {
124+ keywords.append(service.name().toLower());
125+ keywords.append(translations(service.displayName(),
126+ service.trCatalog()));
127+ }
128+
129+ /* Also add the account display names */
130+ Q_FOREACH(Accounts::AccountId id, manager->accountList()) {
131+ Accounts::Account *account = manager->account(id);
132+ if (Q_UNLIKELY(!account)) continue;
133+ QString name = account->displayName().toLower();
134+ if (!name.isEmpty()) {
135+ keywords.append(name);
136+ }
137+ }
138+
139+ delete manager;
140+
141+ setKeywords(keywords);
142+}
143+
144+ItemBase *Plugin::createItem(const QVariantMap &staticData,
145+ QObject *parent)
146+{
147+ return new Item(staticData, parent);
148+}
149+
150+#include "plugin.moc"
151
152=== added file 'system-settings-plugin/plugin.h'
153--- system-settings-plugin/plugin.h 1970-01-01 00:00:00 +0000
154+++ system-settings-plugin/plugin.h 2015-02-02 15:22:49 +0000
155@@ -0,0 +1,36 @@
156+/*
157+ * Copyright (C) 2015 Canonical Ltd.
158+ *
159+ * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
160+ *
161+ * This program is free software: you can redistribute it and/or modify it
162+ * under the terms of the GNU General Public License version 3, as published
163+ * by the Free Software Foundation.
164+ *
165+ * This program is distributed in the hope that it will be useful, but
166+ * WITHOUT ANY WARRANTY; without even the implied warranties of
167+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
168+ * PURPOSE. See the GNU General Public License for more details.
169+ *
170+ * You should have received a copy of the GNU General Public License along
171+ * with this program. If not, see <http://www.gnu.org/licenses/>.
172+ */
173+
174+#ifndef ONLINE_ACCOUNTS_SYSTEM_SETTINGS_PLUGIN_H
175+#define ONLINE_ACCOUNTS_SYSTEM_SETTINGS_PLUGIN_H
176+
177+#include <QObject>
178+#include <SystemSettings/PluginInterface>
179+
180+class Plugin: public QObject, public SystemSettings::PluginInterface2
181+{
182+ Q_OBJECT
183+ Q_PLUGIN_METADATA(IID "com.ubuntu.SystemSettings.PluginInterface/2.0")
184+ Q_INTERFACES(SystemSettings::PluginInterface2)
185+
186+public:
187+ SystemSettings::ItemBase *createItem(const QVariantMap &staticData,
188+ QObject *parent = 0);
189+};
190+
191+#endif // ONLINE_ACCOUNTS_SYSTEM_SETTINGS_PLUGIN_H
192
193=== modified file 'system-settings-plugin/system-settings-plugin.pro'
194--- system-settings-plugin/system-settings-plugin.pro 2014-08-13 13:11:06 +0000
195+++ system-settings-plugin/system-settings-plugin.pro 2015-02-02 15:22:49 +0000
196@@ -1,7 +1,27 @@
197 include(../common-project-config.pri)
198 include($${TOP_SRC_DIR}/common-vars.pri)
199
200-TEMPLATE=aux
201+TEMPLATE=lib
202+TARGET = online-accounts
203+
204+CONFIG += \
205+ link_pkgconfig \
206+ plugin \
207+ qt
208+
209+QT += \
210+ core \
211+ qml
212+
213+PKGCONFIG += \
214+ SystemSettings \
215+ accounts-qt5
216+
217+SOURCES += \
218+ plugin.cpp
219+
220+HEADERS += \
221+ plugin.h
222
223 QML_SOURCES = \
224 AccountEditPage.qml \
225@@ -19,6 +39,9 @@
226 settings.path = $${PLUGIN_MANIFEST_DIR}
227 INSTALLS += settings
228
229+target.path = $${PLUGIN_MODULE_DIR}
230+INSTALLS += target
231+
232 image.files = settings-accounts.svg
233 image.path = $${PLUGIN_MANIFEST_DIR}/icons
234 INSTALLS += image
235
236=== added directory 'tests/system-settings-plugin'
237=== added file 'tests/system-settings-plugin/system-settings-plugin.pro'
238--- tests/system-settings-plugin/system-settings-plugin.pro 1970-01-01 00:00:00 +0000
239+++ tests/system-settings-plugin/system-settings-plugin.pro 2015-02-02 15:22:49 +0000
240@@ -0,0 +1,32 @@
241+include(../../common-project-config.pri)
242+
243+TARGET = tst_plugin
244+
245+CONFIG += \
246+ debug \
247+ link_pkgconfig
248+
249+QT += \
250+ core \
251+ qml \
252+ testlib
253+
254+PKGCONFIG += \
255+ SystemSettings \
256+ accounts-qt5
257+
258+SYSTEM_SETTINGS_PLUGIN_DIR = $${TOP_SRC_DIR}/system-settings-plugin
259+
260+INCLUDEPATH += \
261+ $${SYSTEM_SETTINGS_PLUGIN_DIR}
262+
263+SOURCES += \
264+ $${SYSTEM_SETTINGS_PLUGIN_DIR}/plugin.cpp \
265+ tst_plugin.cpp
266+
267+HEADERS += \
268+ $${SYSTEM_SETTINGS_PLUGIN_DIR}/plugin.h
269+
270+check.commands = "xvfb-run -s '-screen 0 640x480x24' -a dbus-test-runner -t ./$${TARGET}"
271+check.depends = $${TARGET}
272+QMAKE_EXTRA_TARGETS += check
273
274=== added file 'tests/system-settings-plugin/tst_plugin.cpp'
275--- tests/system-settings-plugin/tst_plugin.cpp 1970-01-01 00:00:00 +0000
276+++ tests/system-settings-plugin/tst_plugin.cpp 2015-02-02 15:22:49 +0000
277@@ -0,0 +1,292 @@
278+/*
279+ * Copyright (C) 2014 Canonical Ltd.
280+ *
281+ * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
282+ *
283+ * This file is part of online-accounts-ui
284+ *
285+ * This program is free software: you can redistribute it and/or modify it
286+ * under the terms of the GNU General Public License version 3, as published
287+ * by the Free Software Foundation.
288+ *
289+ * This program is distributed in the hope that it will be useful, but
290+ * WITHOUT ANY WARRANTY; without even the implied warranties of
291+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
292+ * PURPOSE. See the GNU General Public License for more details.
293+ *
294+ * You should have received a copy of the GNU General Public License along
295+ * with this program. If not, see <http://www.gnu.org/licenses/>.
296+ */
297+
298+#include <Accounts/Account>
299+#include <Accounts/Manager>
300+
301+#include <QDebug>
302+#include <QDir>
303+#include <QDomDocument>
304+#include <QDomElement>
305+#include <QFile>
306+#include <QSignalSpy>
307+#include <QTemporaryDir>
308+#include <QTest>
309+
310+#include <SystemSettings/ItemBase>
311+
312+#include "plugin.h"
313+
314+namespace QTest {
315+template<>
316+char *toString(const QSet<QString> &set)
317+{
318+ QByteArray ba = "QSet<QString>(";
319+ QStringList list = set.toList();
320+ ba += list.join(", ");
321+ ba += ")";
322+ return qstrdup(ba.data());
323+}
324+} // QTest namespace
325+
326+/* mocking libintl { */
327+static QHash<QString,QHash<QByteArray,QByteArray> > m_translations;
328+extern "C" {
329+char *dgettext(const char *domainname, const char *msgid)
330+{
331+ return (char *)m_translations[domainname].value(msgid).data();
332+}
333+char *dcgettext(const char *__domainname, const char *__msgid, int __category)
334+{
335+ Q_UNUSED(__category);
336+ return dgettext(__domainname, __msgid);
337+}
338+} // extern C
339+/* } mocking libintl */
340+
341+class PluginTest: public QObject
342+{
343+ Q_OBJECT
344+
345+ struct FileData {
346+ FileData() {}
347+ FileData(const QString &name, const QString &domain):
348+ name(name), domain(domain) {}
349+ QString name;
350+ QString domain;
351+ };
352+
353+public:
354+ PluginTest();
355+
356+private Q_SLOTS:
357+ void testKeywords_data();
358+ void testKeywords();
359+
360+private:
361+ void setDataDir(const QTemporaryDir &dir);
362+ void writeProvider(const QString &id, const QString &name,
363+ const QString &domain);
364+ void writeService(const QString &id, const QString &name,
365+ const QString &domain);
366+ void writeLibaccountsFile(const QString &type, const QString &id,
367+ const QString &name, const QString &domain);
368+ void createAccount(const QString &name);
369+
370+private:
371+ QHash<QString,FileData> m_providersData;
372+ QHash<QString,FileData> m_servicesData;
373+ QDir m_dataDir;
374+};
375+
376+PluginTest::PluginTest():
377+ QObject(0)
378+{
379+ m_providersData["provider_noname"] = FileData("", "");
380+ m_providersData["provider_nodomain"] = FileData("Happy", "");
381+ m_providersData["provider_translated"] = FileData("Joyful", "translations1");
382+
383+ m_servicesData["service_nodomain"] = FileData("Sad", "");
384+ m_servicesData["service_translated"] = FileData("Depressed", "translations1");
385+ m_servicesData["service_translated2"] = FileData("Depressed", "translations2");
386+
387+ m_translations["translations1"]["Happy"] = "Contento";
388+ m_translations["translations1"]["Joyful"] = "Gioioso";
389+ m_translations["translations1"]["Sad"] = "Triste";
390+ m_translations["translations1"]["Depressed"] = "Depresso1";
391+ m_translations["translations1"]["Black"] = "Nero";
392+ m_translations["translations1"]["White"] = "Bianco";
393+
394+ m_translations["translations2"]["Depressed"] = "Depresso2";
395+}
396+
397+void PluginTest::setDataDir(const QTemporaryDir &dir)
398+{
399+ QVERIFY(dir.isValid());
400+
401+ m_dataDir = QDir(dir.path());
402+
403+ QByteArray dataPath = dir.path().toUtf8();
404+ qputenv("ACCOUNTS", dataPath);
405+ qputenv("AG_PROVIDERS", dataPath);
406+ qputenv("AG_SERVICES", dataPath);
407+}
408+
409+void PluginTest::writeProvider(const QString &id, const QString &name,
410+ const QString &domain)
411+{
412+ writeLibaccountsFile("provider", id, name, domain);
413+}
414+
415+void PluginTest::writeService(const QString &id, const QString &name,
416+ const QString &domain)
417+{
418+ writeLibaccountsFile("service", id, name, domain);
419+}
420+
421+void PluginTest::writeLibaccountsFile(const QString &type, const QString &id,
422+ const QString &name, const QString &domain)
423+{
424+ QDomDocument doc;
425+ QDomElement root = doc.createElement(type);
426+ root.setAttribute("id", id);
427+ doc.appendChild(root);
428+
429+ QDomElement nameTag = doc.createElement("name");
430+ nameTag.appendChild(doc.createTextNode(name));
431+ root.appendChild(nameTag);
432+
433+ QDomElement domainTag = doc.createElement("translations");
434+ domainTag.appendChild(doc.createTextNode(domain));
435+ root.appendChild(domainTag);
436+
437+ if (type == "service") {
438+ QDomElement typeTag = doc.createElement("type");
439+ typeTag.appendChild(doc.createTextNode("something"));
440+ root.appendChild(typeTag);
441+ }
442+
443+ QFile file(m_dataDir.filePath(id + "." + type));
444+ if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
445+ qWarning() << "Could not write file" << file.fileName();
446+ return;
447+ }
448+
449+ file.write(doc.toString().toUtf8());
450+}
451+
452+void PluginTest::createAccount(const QString &name)
453+{
454+ Accounts::Manager *manager = new Accounts::Manager;
455+
456+ Accounts::Account *account = manager->createAccount("any");
457+ account->setDisplayName(name);
458+ account->syncAndBlock();
459+
460+ delete manager;
461+}
462+
463+void PluginTest::testKeywords_data()
464+{
465+ QTest::addColumn<QStringList>("providers");
466+ QTest::addColumn<QStringList>("services");
467+ QTest::addColumn<QStringList>("accountNames");
468+ QTest::addColumn<QStringList>("keywords");
469+
470+ QTest::newRow("provider, no name") <<
471+ (QStringList() << "provider_noname") <<
472+ QStringList() <<
473+ QStringList() <<
474+ (QStringList() << "provider_noname");
475+
476+ QTest::newRow("provider, untranslated") <<
477+ (QStringList() << "provider_nodomain") <<
478+ QStringList() <<
479+ QStringList() <<
480+ (QStringList() << "provider_nodomain" << "happy");
481+
482+ QTest::newRow("provider, translated") <<
483+ (QStringList() << "provider_translated") <<
484+ QStringList() <<
485+ QStringList() <<
486+ (QStringList() << "provider_translated" << "joyful" << "gioioso");
487+
488+ QTest::newRow("service, untranslated") <<
489+ QStringList() <<
490+ (QStringList() << "service_nodomain") <<
491+ QStringList() <<
492+ (QStringList() << "service_nodomain" << "sad");
493+
494+ QTest::newRow("service, translated 1") <<
495+ QStringList() <<
496+ (QStringList() << "service_translated") <<
497+ QStringList() <<
498+ (QStringList() << "service_translated" << "depressed" << "depresso1");
499+
500+ QTest::newRow("service, translated 2") <<
501+ QStringList() <<
502+ (QStringList() << "service_translated2") <<
503+ QStringList() <<
504+ (QStringList() << "service_translated2" << "depressed" << "depresso2");
505+
506+ QTest::newRow("one account, one word") <<
507+ QStringList() <<
508+ QStringList() <<
509+ (QStringList() << "tom@example.com") <<
510+ (QStringList() << "tom@example.com");
511+
512+ QTest::newRow("one account, many words") <<
513+ QStringList() <<
514+ QStringList() <<
515+ (QStringList() << "My little sweet account") <<
516+ (QStringList() << "my little sweet account");
517+
518+ QTest::newRow("combined") <<
519+ (QStringList() << "provider_translated" << "provider_nodomain") <<
520+ (QStringList() << "service_translated" << "service_translated2") <<
521+ (QStringList() << "john@invalid" << "harry@mysite.com") <<
522+ (QStringList() << "provider_translated" << "joyful" << "gioioso" <<
523+ "provider_nodomain" << "happy" <<
524+ "service_translated" << "depressed" << "depresso1" <<
525+ "service_translated2" << "depressed" << "depresso2" <<
526+ "john@invalid" << "harry@mysite.com");
527+}
528+
529+void PluginTest::testKeywords()
530+{
531+ QFETCH(QStringList, providers);
532+ QFETCH(QStringList, services);
533+ QFETCH(QStringList, accountNames);
534+ QFETCH(QStringList, keywords);
535+
536+ QTemporaryDir dataDir;
537+
538+ setDataDir(dataDir);
539+
540+ /* Create the needed files */
541+ Q_FOREACH(const QString &providerId, providers) {
542+ writeProvider(providerId,
543+ m_providersData[providerId].name,
544+ m_providersData[providerId].domain);
545+ }
546+
547+ Q_FOREACH(const QString &serviceId, services) {
548+ writeService(serviceId,
549+ m_servicesData[serviceId].name,
550+ m_servicesData[serviceId].domain);
551+ }
552+
553+ /* create the accounts */
554+ Q_FOREACH(const QString &displayName, accountNames) {
555+ createAccount(displayName);
556+ }
557+
558+ /* Now do the actual test */
559+ Plugin plugin;
560+
561+ SystemSettings::ItemBase *item = plugin.createItem(QVariantMap());
562+ QStringList pluginKeywords = item->keywords();
563+
564+ QCOMPARE(pluginKeywords.toSet(), keywords.toSet());
565+}
566+
567+QTEST_MAIN(PluginTest);
568+
569+#include "tst_plugin.moc"
570
571=== modified file 'tests/tests.pro'
572--- tests/tests.pro 2014-10-03 14:56:11 +0000
573+++ tests/tests.pro 2015-02-02 15:22:49 +0000
574@@ -5,4 +5,5 @@
575 client \
576 online-accounts-service \
577 online-accounts-ui \
578- plugin
579+ plugin \
580+ system-settings-plugin

Subscribers

People subscribed via source and target branches