Merge lp:~stolowski/unity-scope-click/local-departments into lp:unity-scope-click/devel
- local-departments
- Merge into devel
Status: | Work in progress |
---|---|
Proposed branch: | lp:~stolowski/unity-scope-click/local-departments |
Merge into: | lp:unity-scope-click/devel |
Diff against target: |
1506 lines (+902/-36) 24 files modified
debian/control (+1/-0) libclickscope/click/CMakeLists.txt (+4/-0) libclickscope/click/departments-db.cpp (+318/-0) libclickscope/click/departments-db.h (+100/-0) libclickscope/click/interface.cpp (+8/-2) libclickscope/click/interface.h (+3/-1) libclickscope/click/package.cpp (+9/-0) libclickscope/click/package.h (+2/-0) libclickscope/click/preview.cpp (+46/-7) libclickscope/click/preview.h (+9/-3) libclickscope/tests/CMakeLists.txt (+5/-1) libclickscope/tests/test_departments-db.cpp (+228/-0) libclickscope/tests/test_index.cpp (+4/-2) scope/clickapps/CMakeLists.txt (+2/-1) scope/clickapps/apps-query.cpp (+82/-7) scope/clickapps/apps-query.h (+3/-1) scope/clickapps/apps-scope.cpp (+11/-2) scope/clickapps/apps-scope.h (+4/-0) scope/clickstore/CMakeLists.txt (+2/-1) scope/clickstore/store-query.cpp (+39/-1) scope/clickstore/store-query.h (+3/-1) scope/clickstore/store-scope.cpp (+12/-2) scope/clickstore/store-scope.h (+2/-0) scope/tests/test_query.cpp (+5/-4) |
To merge this branch: | bzr merge lp:~stolowski/unity-scope-click/local-departments |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alejandro J. Cura (community) | Needs Fixing | ||
Review via email: mp+224870@code.launchpad.net |
Commit message
Support for departments in click apps scope, for locally installed apps.
Description of the change
Support for departments in click apps scope, for locally installed apps.
Note: this is still WIP, and needs a change to /api/v1/package server call (as described on https:/
- 315. By Paweł Stołowski
-
Use recursive sql query when fetching packages from a department.
- 316. By Paweł Stołowski
-
Depend on sqlite >= 3.8.5 to ensure recursive sql statement is supported at runtime.
- 317. By Paweł Stołowski
-
Uncomment unlink.
Unmerged revisions
- 317. By Paweł Stołowski
-
Uncomment unlink.
- 316. By Paweł Stołowski
-
Depend on sqlite >= 3.8.5 to ensure recursive sql statement is supported at runtime.
- 315. By Paweł Stołowski
-
Use recursive sql query when fetching packages from a department.
- 314. By Paweł Stołowski
-
Apply department filter when querying for locally installed apps.
- 313. By Paweł Stołowski
-
Throw on empty arguments to database store methods. Keep database in clickscope subdir.
- 312. By Paweł Stołowski
-
Store package - department mapping when displaying the preview.
- 311. By Paweł Stołowski
-
More checks in the test.
- 310. By Paweł Stołowski
-
Test department name updates.
- 309. By Paweł Stołowski
-
Fixes around table definitions; test for no duplicated records.
- 308. By Paweł Stołowski
-
Populdate department in details.
Preview Diff
1 | === modified file 'debian/control' |
2 | --- debian/control 2014-06-23 15:00:28 +0000 |
3 | +++ debian/control 2014-07-02 12:34:49 +0000 |
4 | @@ -29,6 +29,7 @@ |
5 | ubuntu-app-launch-tools, |
6 | ubuntu-download-manager, |
7 | ubuntu-sdk-libs, |
8 | + sqlite3 (>= 3.8.5), |
9 | ${misc:Depends}, |
10 | ${shlibs:Depends}, |
11 | Breaks: unity (<< 7.0), |
12 | |
13 | === modified file 'libclickscope/click/CMakeLists.txt' |
14 | --- libclickscope/click/CMakeLists.txt 2014-06-23 15:00:28 +0000 |
15 | +++ libclickscope/click/CMakeLists.txt 2014-07-02 12:34:49 +0000 |
16 | @@ -1,6 +1,7 @@ |
17 | SET (CMAKE_INCLUDE_CURRENT_DIR ON) |
18 | SET (CMAKE_AUTOMOC ON) |
19 | find_package (Qt5Core REQUIRED) |
20 | +find_package (Qt5Sql REQUIRED) |
21 | pkg_check_modules(JSON_CPP REQUIRED jsoncpp) |
22 | |
23 | add_definitions( |
24 | @@ -14,6 +15,7 @@ |
25 | download-manager.cpp |
26 | department-lookup.cpp |
27 | departments.cpp |
28 | + departments-db.cpp |
29 | highlights.cpp |
30 | index.cpp |
31 | interface.cpp |
32 | @@ -30,6 +32,8 @@ |
33 | webclient.cpp |
34 | ) |
35 | |
36 | +qt5_use_modules(${SCOPE_LIB_NAME} Sql) |
37 | + |
38 | include_directories( |
39 | ${JSON_CPP_INCLUDE_DIRS} |
40 | ${CMAKE_SOURCE_DIR}/libclickscope |
41 | |
42 | === added file 'libclickscope/click/departments-db.cpp' |
43 | --- libclickscope/click/departments-db.cpp 1970-01-01 00:00:00 +0000 |
44 | +++ libclickscope/click/departments-db.cpp 2014-07-02 12:34:49 +0000 |
45 | @@ -0,0 +1,318 @@ |
46 | +/* |
47 | + * Copyright (C) 2014 Canonical Ltd. |
48 | + * |
49 | + * This program is free software: you can redistribute it and/or modify it |
50 | + * under the terms of the GNU General Public License version 3, as published |
51 | + * by the Free Software Foundation. |
52 | + * |
53 | + * This program is distributed in the hope that it will be useful, but |
54 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
55 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
56 | + * PURPOSE. See the GNU General Public License for more details. |
57 | + * |
58 | + * You should have received a copy of the GNU General Public License along |
59 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
60 | + * |
61 | + * In addition, as a special exception, the copyright holders give |
62 | + * permission to link the code of portions of this program with the |
63 | + * OpenSSL library under certain conditions as described in each |
64 | + * individual source file, and distribute linked combinations |
65 | + * including the two. |
66 | + * You must obey the GNU General Public License in all respects |
67 | + * for all of the code used other than OpenSSL. If you modify |
68 | + * file(s) with this exception, you may extend this exception to your |
69 | + * version of the file(s), but you are not obligated to do so. If you |
70 | + * do not wish to do so, delete this exception statement from your |
71 | + * version. If you delete this exception statement from all source |
72 | + * files in the program, then also delete it here. |
73 | + */ |
74 | + |
75 | +#include "departments-db.h" |
76 | +#include <stdexcept> |
77 | +#include <iostream> |
78 | +#include <QSqlError> |
79 | +#include <QSqlRecord> |
80 | +#include <QVariant> |
81 | +#include <QStandardPaths> |
82 | +#include <QDir> |
83 | + |
84 | +namespace click |
85 | +{ |
86 | + |
87 | +std::unique_ptr<click::DepartmentsDb> DepartmentsDb::create_db() |
88 | +{ |
89 | + auto const path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); |
90 | + if (!path.isEmpty()) |
91 | + { |
92 | + QDir("/").mkpath(path); |
93 | + const std::string dbpath = path.toStdString() + "/clickscope/click-departments.db"; |
94 | + return std::unique_ptr<DepartmentsDb>(new DepartmentsDb(dbpath)); |
95 | + } |
96 | + throw std::runtime_error("Cannot determine cache directory"); |
97 | +} |
98 | + |
99 | +DepartmentsDb::DepartmentsDb(const std::string& name) |
100 | +{ |
101 | + init_db(name); |
102 | + |
103 | + delete_pkgmap_query_.reset(new QSqlQuery(db_)); |
104 | + insert_pkgmap_query_.reset(new QSqlQuery(db_)); |
105 | + insert_dept_id_query_.reset(new QSqlQuery(db_)); |
106 | + insert_dept_name_query_.reset(new QSqlQuery(db_)); |
107 | + select_pkgs_by_dept_.reset(new QSqlQuery(db_)); |
108 | + select_pkgs_by_dept_recursive_.reset(new QSqlQuery(db_)); |
109 | + select_parent_dept_.reset(new QSqlQuery(db_)); |
110 | + select_children_depts_.reset(new QSqlQuery(db_)); |
111 | + select_dept_name_.reset(new QSqlQuery(db_)); |
112 | + |
113 | + delete_pkgmap_query_->prepare("DELETE FROM pkgmap WHERE pkgid=:pkgid"); |
114 | + insert_pkgmap_query_->prepare("INSERT OR REPLACE INTO pkgmap (pkgid, deptid) VALUES (:pkgid, :deptid)"); |
115 | + insert_dept_id_query_->prepare("INSERT OR REPLACE INTO depts (deptid, parentid) VALUES (:deptid, :parentid)"); |
116 | + insert_dept_name_query_->prepare("INSERT OR REPLACE INTO deptnames (deptid, locale, name) VALUES (:deptid, :locale, :name)"); |
117 | + select_pkgs_by_dept_->prepare("SELECT pkgid FROM pkgmap WHERE deptid=:deptid"); |
118 | + select_pkgs_by_dept_recursive_->prepare("WITH RECURSIVE recdepts(deptid) AS (SELECT deptid FROM depts_v WHERE deptid=:deptid UNION SELECT depts_v.deptid FROM recdepts,depts_v WHERE recdepts.deptid=depts_v.parentid) SELECT pkgid FROM pkgmap NATURAL JOIN recdepts"); |
119 | + select_children_depts_->prepare("SELECT deptid,(SELECT COUNT(1) from DEPTS_V AS inner WHERE inner.parentid=outer.deptid) FROM DEPTS_V AS outer WHERE parentid=:parentid"); |
120 | + select_parent_dept_->prepare("SELECT parentid FROM depts_v WHERE deptid=:deptid"); |
121 | + select_dept_name_->prepare("SELECT name FROM deptnames WHERE deptid=:deptid AND locale=:locale"); |
122 | +} |
123 | + |
124 | +void DepartmentsDb::init_db(const std::string& name) |
125 | +{ |
126 | + db_ = QSqlDatabase::addDatabase("QSQLITE"); |
127 | + db_.setDatabaseName(QString::fromStdString(name)); |
128 | + if (!db_.open()) |
129 | + { |
130 | + throw std::runtime_error("Cannot open departments database"); |
131 | + } |
132 | + |
133 | + QSqlQuery query; |
134 | + |
135 | + //query.exec("PRAGMA foreign_keys = ON"); |
136 | + |
137 | + // package id -> department id mapping table |
138 | + if (!query.exec("CREATE TABLE IF NOT EXISTS pkgmap (pkgid TEXT, deptid TEXT, CONSTRAINT pkey PRIMARY KEY (pkgid, deptid))")) |
139 | + { |
140 | + report_db_error(query.lastError(), "Failed to create pkgmap table"); |
141 | + } |
142 | + |
143 | + // department id -> parent department id mapping table |
144 | + if (!query.exec("CREATE TABLE IF NOT EXISTS depts (deptid TEXT, parentid TEXT, CONSTRAINT pkey PRIMARY KEY (deptid, parentid), CONSTRAINT fkey FOREIGN KEY (deptid) REFERENCES deptnames(deptid))")) |
145 | + { |
146 | + report_db_error(query.lastError(), "Failed to create depts table"); |
147 | + } |
148 | + |
149 | + // department id, locale -> deparment name mapping table |
150 | + if (!query.exec("CREATE TABLE IF NOT EXISTS deptnames (deptid TEXT, locale TEXT, name TEXT, CONSTRAINT deptuniq PRIMARY KEY (deptid, locale))")) |
151 | + { |
152 | + report_db_error(query.lastError(), "Failed to create depts table"); |
153 | + } |
154 | + |
155 | + // name -> value table for storing arbitrary values such as schema version |
156 | + if (!query.exec("CREATE TABLE IF NOT EXISTS meta (name TEXT PRIMARY KEY, value TEXT)")) |
157 | + { |
158 | + report_db_error(query.lastError(), "Failed to create meta table"); |
159 | + } |
160 | + query.exec("INSERT INTO meta (name, value) VALUES ('version', 1)"); |
161 | + |
162 | + // view of the depts table that automatically adds fake "" department for root departments |
163 | + if (!query.exec("CREATE VIEW IF NOT EXISTS depts_v AS SELECT deptid, parentid FROM depts UNION SELECT deptid,'' AS parentid FROM deptnames WHERE NOT EXISTS " |
164 | + "(SELECT * FROM depts WHERE depts.deptid=deptnames.deptid)")) |
165 | + { |
166 | + report_db_error(query.lastError(), "Failed to create depts_v view"); |
167 | + } |
168 | +} |
169 | + |
170 | +void DepartmentsDb::report_db_error(const QSqlError& error, const std::string& message) |
171 | +{ |
172 | + throw std::runtime_error(message + ": " + error.text().toStdString()); |
173 | +} |
174 | + |
175 | +std::string DepartmentsDb::get_department_name(const std::string& department_id, const std::list<std::string>& locales) |
176 | +{ |
177 | + for (auto const& locale: locales) |
178 | + { |
179 | + select_dept_name_->bindValue(":deptid", QVariant(QString::fromStdString(department_id))); |
180 | + select_dept_name_->bindValue(":locale", QVariant(QString::fromStdString(locale))); |
181 | + |
182 | + if (!select_dept_name_->exec()) |
183 | + { |
184 | + report_db_error(select_dept_name_->lastError(), "Failed to query for department name of " + department_id + ", locale " + locale); |
185 | + } |
186 | + |
187 | + if (select_dept_name_->next()) |
188 | + { |
189 | + return select_dept_name_->value(0).toString().toStdString(); |
190 | + } |
191 | + } |
192 | + throw std::logic_error("No name for department " + department_id); |
193 | +} |
194 | + |
195 | +std::string DepartmentsDb::get_parent_department_id(const std::string& department_id) |
196 | +{ |
197 | + select_parent_dept_->bindValue(":deptid", QVariant(QString::fromStdString(department_id))); |
198 | + if (!select_parent_dept_->exec()) |
199 | + { |
200 | + report_db_error(select_parent_dept_->lastError(), "Failed to query for parent department " + department_id); |
201 | + } |
202 | + if (!select_parent_dept_->next()) |
203 | + { |
204 | + throw std::logic_error("Unknown department '" + department_id + "'"); |
205 | + } |
206 | + return select_parent_dept_->value(0).toString().toStdString(); |
207 | +} |
208 | + |
209 | +std::list<DepartmentsDb::DepartmentInfo> DepartmentsDb::get_children_departments(const std::string& department_id) |
210 | +{ |
211 | + // TODO: this should only return departments that have results, and set 'has_children' flag on the same basis. |
212 | + // to be fixed when new sqlite3 is available. |
213 | + select_children_depts_->bindValue(":parentid", QVariant(QString::fromStdString(department_id))); |
214 | + if (!select_children_depts_->exec()) |
215 | + { |
216 | + report_db_error(select_children_depts_->lastError(), "Failed to query for children departments of " + department_id); |
217 | + } |
218 | + |
219 | + std::list<DepartmentInfo> depts; |
220 | + while (select_children_depts_->next()) |
221 | + { |
222 | + const DepartmentInfo inf(select_children_depts_->value(0).toString().toStdString(), select_children_depts_->value(1).toBool()); |
223 | + depts.push_back(inf); |
224 | + } |
225 | + |
226 | + return depts; |
227 | +} |
228 | + |
229 | +std::unordered_set<std::string> DepartmentsDb::get_packages_for_department(const std::string& department_id, bool recursive) |
230 | +{ |
231 | + std::unordered_set<std::string> pkgs; |
232 | + QSqlQuery *query = recursive ? select_pkgs_by_dept_recursive_.get() : select_pkgs_by_dept_.get(); |
233 | + query->bindValue(":deptid", QVariant(QString::fromStdString(department_id))); |
234 | + if (!query->exec()) |
235 | + { |
236 | + report_db_error(query->lastError(), "Failed to query for packages of department " + department_id); |
237 | + } |
238 | + while (query->next()) |
239 | + { |
240 | + pkgs.insert(query->value(0).toString().toStdString()); |
241 | + } |
242 | + return pkgs; |
243 | +} |
244 | + |
245 | +void DepartmentsDb::store_package_mapping(const std::string& package_id, const std::set<std::string>& department_ids) |
246 | +{ |
247 | + if (package_id.empty()) |
248 | + { |
249 | + throw std::logic_error("Invalid empty package_id"); |
250 | + } |
251 | + |
252 | + if (department_ids.size() == 0) |
253 | + { |
254 | + throw std::logic_error("Invalid empty departments list"); |
255 | + } |
256 | + |
257 | + if (!db_.transaction()) |
258 | + { |
259 | + std::cerr << "Failed to start transaction" << std::endl; |
260 | + } |
261 | + |
262 | + // delete package mapping first from any departments |
263 | + delete_pkgmap_query_->bindValue(":pkgid", QVariant(QString::fromStdString(package_id))); |
264 | + delete_pkgmap_query_->exec(); |
265 | + |
266 | + for (auto const& dept: department_ids) |
267 | + { |
268 | + if (dept.empty()) |
269 | + { |
270 | + throw std::logic_error("Invalid empty department id"); |
271 | + } |
272 | + |
273 | + insert_pkgmap_query_->bindValue(":pkgid", QVariant(QString::fromStdString(package_id))); |
274 | + insert_pkgmap_query_->bindValue(":deptid", QVariant(QString::fromStdString(dept))); |
275 | + if (!insert_pkgmap_query_->exec()) |
276 | + { |
277 | + if (!db_.rollback()) |
278 | + { |
279 | + std::cerr << "Failed to rollback transaction" << std::endl; |
280 | + } |
281 | + report_db_error(insert_pkgmap_query_->lastError(), "Failed to insert into pkgmap"); |
282 | + } |
283 | + } |
284 | + |
285 | + if (!db_.commit()) |
286 | + { |
287 | + std::cerr << "Failed to commit transaction" << std::endl; |
288 | + } |
289 | +} |
290 | + |
291 | +void DepartmentsDb::store_department_mapping(const std::string& department_id, const std::string& parent_department_id) |
292 | +{ |
293 | + if (department_id.empty()) |
294 | + { |
295 | + throw std::logic_error("Invalid empty department id"); |
296 | + } |
297 | + |
298 | + if (parent_department_id.empty()) |
299 | + { |
300 | + throw std::logic_error("Invalid empty parent department id"); |
301 | + } |
302 | + |
303 | + insert_dept_id_query_->bindValue(":deptid", QVariant(QString::fromStdString(department_id))); |
304 | + insert_dept_id_query_->bindValue(":parentid", QVariant(QString::fromStdString(parent_department_id))); |
305 | + if (!insert_dept_id_query_->exec()) |
306 | + { |
307 | + report_db_error(insert_dept_id_query_->lastError(), "Failed to insert into depts"); |
308 | + } |
309 | +} |
310 | + |
311 | +void DepartmentsDb::store_department_name(const std::string& department_id, const std::string& locale, const std::string& name) |
312 | +{ |
313 | + if (department_id.empty()) |
314 | + { |
315 | + throw std::logic_error("Invalid empty department id"); |
316 | + } |
317 | + |
318 | + if (name.empty()) |
319 | + { |
320 | + throw std::logic_error("Invalid empty department name"); |
321 | + } |
322 | + |
323 | + insert_dept_name_query_->bindValue(":deptid", QVariant(QString::fromStdString(department_id))); |
324 | + insert_dept_name_query_->bindValue(":locale", QVariant(QString::fromStdString(locale))); |
325 | + insert_dept_name_query_->bindValue(":name", QVariant(QString::fromStdString(name))); |
326 | + |
327 | + if (!insert_dept_name_query_->exec()) |
328 | + { |
329 | + report_db_error(insert_dept_name_query_->lastError(), "Failed to insert into deptnames"); |
330 | + } |
331 | +} |
332 | + |
333 | +int DepartmentsDb::department_mapping_count() const |
334 | +{ |
335 | + QSqlQuery q(db_); |
336 | + if (!q.exec("SELECT COUNT(*) FROM depts") || !q.next()) |
337 | + { |
338 | + report_db_error(q.lastError(), "Failed to query depts table"); |
339 | + } |
340 | + return q.value(0).toInt(); |
341 | +} |
342 | + |
343 | +int DepartmentsDb::package_count() const |
344 | +{ |
345 | + QSqlQuery q(db_); |
346 | + if (!q.exec("SELECT COUNT(*) FROM pkgmap") || !q.next()) |
347 | + { |
348 | + report_db_error(q.lastError(), "Failed to query pkgmap table"); |
349 | + } |
350 | + return q.value(0).toInt(); |
351 | +} |
352 | + |
353 | +int DepartmentsDb::department_name_count() const |
354 | +{ |
355 | + QSqlQuery q(db_); |
356 | + if (!q.exec("SELECT COUNT(*) FROM deptnames") || !q.next()) |
357 | + { |
358 | + report_db_error(q.lastError(), "Failed to query deptnames table"); |
359 | + } |
360 | + return q.value(0).toInt(); |
361 | +} |
362 | + |
363 | +} |
364 | |
365 | === added file 'libclickscope/click/departments-db.h' |
366 | --- libclickscope/click/departments-db.h 1970-01-01 00:00:00 +0000 |
367 | +++ libclickscope/click/departments-db.h 2014-07-02 12:34:49 +0000 |
368 | @@ -0,0 +1,100 @@ |
369 | +/* |
370 | + * Copyright (C) 2014 Canonical Ltd. |
371 | + * |
372 | + * This program is free software: you can redistribute it and/or modify it |
373 | + * under the terms of the GNU General Public License version 3, as published |
374 | + * by the Free Software Foundation. |
375 | + * |
376 | + * This program is distributed in the hope that it will be useful, but |
377 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
378 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
379 | + * PURPOSE. See the GNU General Public License for more details. |
380 | + * |
381 | + * You should have received a copy of the GNU General Public License along |
382 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
383 | + * |
384 | + * In addition, as a special exception, the copyright holders give |
385 | + * permission to link the code of portions of this program with the |
386 | + * OpenSSL library under certain conditions as described in each |
387 | + * individual source file, and distribute linked combinations |
388 | + * including the two. |
389 | + * You must obey the GNU General Public License in all respects |
390 | + * for all of the code used other than OpenSSL. If you modify |
391 | + * file(s) with this exception, you may extend this exception to your |
392 | + * version of the file(s), but you are not obligated to do so. If you |
393 | + * do not wish to do so, delete this exception statement from your |
394 | + * version. If you delete this exception statement from all source |
395 | + * files in the program, then also delete it here. |
396 | + */ |
397 | + |
398 | +#ifndef CLICK_DEPARTMENTS_DB_H |
399 | +#define CLICK_DEPARTMENTS_DB_H |
400 | + |
401 | +#include <string> |
402 | +#include <set> |
403 | +#include <unordered_set> |
404 | +#include <list> |
405 | +#include <QSqlDatabase> |
406 | +#include <QSqlQuery> |
407 | +#include <memory> |
408 | + |
409 | +class QSqlError; |
410 | + |
411 | +namespace click |
412 | +{ |
413 | + |
414 | +class DepartmentsDb final |
415 | +{ |
416 | +public: |
417 | + struct DepartmentInfo |
418 | + { |
419 | + DepartmentInfo(const std::string &id, bool children): id(id), has_children(children) {} |
420 | + std::string id; |
421 | + bool has_children; |
422 | + |
423 | + bool operator==(const DepartmentInfo& other) const |
424 | + { |
425 | + return id == other.id && has_children == other.has_children; |
426 | + } |
427 | + }; |
428 | + |
429 | + DepartmentsDb(const std::string& name); |
430 | + DepartmentsDb(const DepartmentsDb& other) = delete; |
431 | + DepartmentsDb& operator=(const DepartmentsDb&) = delete; |
432 | + |
433 | + std::string get_department_name(const std::string& department_id, const std::list<std::string>& locales); |
434 | + std::unordered_set<std::string> get_packages_for_department(const std::string& department_id, bool recursive = true); |
435 | + std::string get_parent_department_id(const std::string& department_id); |
436 | + std::list<DepartmentInfo> get_children_departments(const std::string& department_id); |
437 | + |
438 | + // FIXME: package can belong to only one department, get rid of set |
439 | + void store_package_mapping(const std::string& package_id, const std::set<std::string>& department_ids); |
440 | + void store_department_mapping(const std::string& department_id, const std::string& parent_department_id); |
441 | + void store_department_name(const std::string& department_id, const std::string& locale, const std::string& name); |
442 | + |
443 | + // these methods are mostly for tests |
444 | + int department_mapping_count() const; |
445 | + int package_count() const; |
446 | + int department_name_count() const; |
447 | + |
448 | + static std::unique_ptr<DepartmentsDb> create_db(); |
449 | + |
450 | +private: |
451 | + void init_db(const std::string& name); |
452 | + static void report_db_error(const QSqlError& error, const std::string& message); |
453 | + |
454 | + QSqlDatabase db_; |
455 | + std::unique_ptr<QSqlQuery> delete_pkgmap_query_; |
456 | + std::unique_ptr<QSqlQuery> insert_pkgmap_query_; |
457 | + std::unique_ptr<QSqlQuery> insert_dept_id_query_; |
458 | + std::unique_ptr<QSqlQuery> insert_dept_name_query_; |
459 | + std::unique_ptr<QSqlQuery> select_pkgs_by_dept_; |
460 | + std::unique_ptr<QSqlQuery> select_pkgs_by_dept_recursive_; |
461 | + std::unique_ptr<QSqlQuery> select_parent_dept_; |
462 | + std::unique_ptr<QSqlQuery> select_children_depts_; |
463 | + std::unique_ptr<QSqlQuery> select_dept_name_; |
464 | +}; |
465 | + |
466 | +} |
467 | + |
468 | +#endif |
469 | |
470 | === modified file 'libclickscope/click/interface.cpp' |
471 | --- libclickscope/click/interface.cpp 2014-06-16 15:38:49 +0000 |
472 | +++ libclickscope/click/interface.cpp 2014-07-02 12:34:49 +0000 |
473 | @@ -228,13 +228,15 @@ |
474 | * |
475 | * Find all of the installed apps matching @search_query in a timeout. |
476 | */ |
477 | -std::vector<click::Application> Interface::find_installed_apps(const std::string& search_query) |
478 | +std::vector<click::Application> Interface::find_installed_apps(const std::string& search_query, |
479 | + const std::unordered_set<std::string>& packages_in_department, |
480 | + bool department_filter) |
481 | { |
482 | std::vector<Application> result; |
483 | |
484 | bool include_desktop_results = show_desktop_apps(); |
485 | |
486 | - auto enumerator = [&result, this, search_query, include_desktop_results] |
487 | + auto enumerator = [&result, this, search_query, packages_in_department, department_filter, include_desktop_results] |
488 | (const unity::util::IniParser& keyFile, const std::string& filename) |
489 | { |
490 | if (keyFile.has_group(DESKTOP_FILE_GROUP) == false) { |
491 | @@ -250,6 +252,10 @@ |
492 | || Interface::is_non_click_app(QString::fromStdString(filename))) { |
493 | auto app = load_app_from_desktop(keyFile, filename); |
494 | |
495 | + // check if apps is present in current department |
496 | + if (department_filter && packages_in_department.find(app.name) == packages_in_department.end()) |
497 | + return; |
498 | + |
499 | if (search_query.empty()) { |
500 | result.push_back(app); |
501 | } else { |
502 | |
503 | === modified file 'libclickscope/click/interface.h' |
504 | --- libclickscope/click/interface.h 2014-06-16 15:38:49 +0000 |
505 | +++ libclickscope/click/interface.h 2014-07-02 12:34:49 +0000 |
506 | @@ -90,7 +90,9 @@ |
507 | virtual Application load_app_from_desktop(const unity::util::IniParser& keyFile, |
508 | const std::string& filename); |
509 | static std::vector<Application> sort_apps(const std::vector<Application>& apps); |
510 | - virtual std::vector<Application> find_installed_apps(const std::string& search_query); |
511 | + virtual std::vector<Application> find_installed_apps(const std::string& search_query, |
512 | + const std::unordered_set<std::string>& packages_in_department = std::unordered_set<std::string>(), |
513 | + bool department_filter = false); |
514 | |
515 | static bool is_non_click_app(const QString& filename); |
516 | |
517 | |
518 | === modified file 'libclickscope/click/package.cpp' |
519 | --- libclickscope/click/package.cpp 2014-06-26 17:31:28 +0000 |
520 | +++ libclickscope/click/package.cpp 2014-07-02 12:34:49 +0000 |
521 | @@ -126,6 +126,15 @@ |
522 | details.download_url = root[JsonKeys::download_url].asString(); |
523 | details.license = root[JsonKeys::license].asString(); |
524 | |
525 | + if (root[JsonKeys::department].isArray()) |
526 | + { |
527 | + auto const dept_array = root[JsonKeys::department]; |
528 | + if (dept_array.size() > 0) |
529 | + { |
530 | + details.department = dept_array[dept_array.size() - 1].asString(); |
531 | + } |
532 | + } |
533 | + |
534 | // Optional details go here. |
535 | if (root[JsonKeys::version].isString()) |
536 | details.version = root[JsonKeys::version].asString(); |
537 | |
538 | === modified file 'libclickscope/click/package.h' |
539 | --- libclickscope/click/package.h 2014-06-26 17:31:28 +0000 |
540 | +++ libclickscope/click/package.h 2014-07-02 12:34:49 +0000 |
541 | @@ -126,6 +126,7 @@ |
542 | constexpr static const char* terms_of_service{"terms_of_service"}; |
543 | constexpr static const char* license{"license"}; |
544 | constexpr static const char* publisher{"publisher"}; |
545 | + constexpr static const char* department{"department"}; |
546 | constexpr static const char* main_screenshot_url{"screenshot_url"}; |
547 | constexpr static const char* more_screenshot_urls{"screenshot_urls"}; |
548 | constexpr static const char* binary_filesize{"binary_filesize"}; |
549 | @@ -149,6 +150,7 @@ |
550 | json::Value::UInt64 binary_filesize; |
551 | std::string version; |
552 | std::string framework; |
553 | + std::string department; |
554 | }; |
555 | |
556 | std::ostream& operator<<(std::ostream& out, const PackageDetails& details); |
557 | |
558 | === modified file 'libclickscope/click/preview.cpp' |
559 | --- libclickscope/click/preview.cpp 2014-06-23 15:00:28 +0000 |
560 | +++ libclickscope/click/preview.cpp 2014-07-02 12:34:49 +0000 |
561 | @@ -34,6 +34,7 @@ |
562 | #include <click/download-manager.h> |
563 | #include <click/launcher.h> |
564 | #include <click/dbus_constants.h> |
565 | +#include <click/departments-db.h> |
566 | |
567 | #include <boost/algorithm/string/replace.hpp> |
568 | |
569 | @@ -58,16 +59,18 @@ |
570 | Preview::Preview(const unity::scopes::Result& result, |
571 | const unity::scopes::ActionMetadata& metadata, |
572 | const QSharedPointer<click::web::Client>& client, |
573 | - const QSharedPointer<click::network::AccessManager>& nam) |
574 | + const QSharedPointer<click::network::AccessManager>& nam, |
575 | + std::shared_ptr<click::DepartmentsDb> depts) |
576 | : PreviewQueryBase(result, metadata) |
577 | { |
578 | - strategy.reset(choose_strategy(result, metadata, client, nam)); |
579 | + strategy.reset(choose_strategy(result, metadata, client, nam, depts)); |
580 | } |
581 | |
582 | PreviewStrategy* Preview::choose_strategy(const unity::scopes::Result &result, |
583 | const unity::scopes::ActionMetadata &metadata, |
584 | const QSharedPointer<web::Client> &client, |
585 | - const QSharedPointer<click::network::AccessManager>& nam) |
586 | + const QSharedPointer<click::network::AccessManager>& nam, |
587 | + std::shared_ptr<click::DepartmentsDb> depts) |
588 | { |
589 | if (metadata.scope_data().which() != scopes::Variant::Type::Null) { |
590 | auto metadict = metadata.scope_data().get_dict(); |
591 | @@ -86,7 +89,7 @@ |
592 | std::string action_id = metadict["action_id"].get_string(); |
593 | std::string download_url = metadict["download_url"].get_string(); |
594 | if (action_id == click::Preview::Actions::INSTALL_CLICK) { |
595 | - return new InstallingPreview(download_url, result, client, nam); |
596 | + return new InstallingPreview(download_url, result, client, nam, depts); |
597 | } else { |
598 | qWarning() << "unexpected action id " << QString::fromStdString(action_id) |
599 | << " given with download_url" << QString::fromStdString(download_url); |
600 | @@ -346,9 +349,11 @@ |
601 | InstallingPreview::InstallingPreview(const std::string &download_url, |
602 | const unity::scopes::Result &result, |
603 | const QSharedPointer<click::web::Client>& client, |
604 | - const QSharedPointer<click::network::AccessManager> &nam) |
605 | + const QSharedPointer<click::network::AccessManager> &nam, |
606 | + std::shared_ptr<click::DepartmentsDb> depts) |
607 | : PreviewStrategy(result, client), download_url(download_url), |
608 | - downloader(new click::Downloader(nam)) |
609 | + downloader(new click::Downloader(nam)), |
610 | + depts_db(depts) |
611 | { |
612 | } |
613 | |
614 | @@ -383,7 +388,9 @@ |
615 | default: |
616 | std::string object_path = rc.first; |
617 | qDebug() << "Successfully created UDM Download."; |
618 | - populateDetails([this, reply, object_path](const PackageDetails &details){ |
619 | + populateDetails([this, reply, object_path](const PackageDetails &details) { |
620 | + store_department(details); |
621 | + |
622 | reply->push(headerWidgets(details)); |
623 | reply->push(progressBarWidget(object_path)); |
624 | reply->push(descriptionWidgets(details)); |
625 | @@ -403,6 +410,38 @@ |
626 | }); |
627 | } |
628 | |
629 | +void InstallingPreview::store_department(const PackageDetails& details) |
630 | +{ |
631 | + // |
632 | + // store package -> department mapping in sqlite db |
633 | + if (depts_db) |
634 | + { |
635 | + if (!details.department.empty()) |
636 | + { |
637 | + try |
638 | + { |
639 | + depts_db->store_package_mapping(details.package.name, { details.department }); |
640 | + qDebug() << "Storing mapping for" << QString::fromStdString(details.package.name) << ":" << QString::fromStdString(details.department); |
641 | + } |
642 | + catch (const std::exception& e) |
643 | + { |
644 | + qWarning() << "Failed to store package mapping for package '" |
645 | + << QString::fromStdString(details.package.name) |
646 | + << "', department '" << QString::fromStdString(details.department) |
647 | + << "':" << QString::fromStdString(e.what()); |
648 | + } |
649 | + } |
650 | + else |
651 | + { |
652 | + qWarning() << "Department is empty for package" << QString::fromStdString(details.package.name); |
653 | + } |
654 | + } |
655 | + else |
656 | + { |
657 | + qWarning() << "Departments database not available"; |
658 | + } |
659 | +} |
660 | + |
661 | scopes::PreviewWidgetList InstallingPreview::progressBarWidget(const std::string& object_path) |
662 | { |
663 | scopes::PreviewWidgetList widgets; |
664 | |
665 | === modified file 'libclickscope/click/preview.h' |
666 | --- libclickscope/click/preview.h 2014-06-18 04:39:23 +0000 |
667 | +++ libclickscope/click/preview.h 2014-07-02 12:34:49 +0000 |
668 | @@ -49,6 +49,7 @@ |
669 | |
670 | class Manifest; |
671 | class PreviewStrategy; |
672 | +class DepartmentsDb; |
673 | |
674 | class Preview : public unity::scopes::PreviewQueryBase |
675 | { |
676 | @@ -57,7 +58,8 @@ |
677 | PreviewStrategy* choose_strategy(const unity::scopes::Result& result, |
678 | const unity::scopes::ActionMetadata& metadata, |
679 | const QSharedPointer<web::Client> &client, |
680 | - const QSharedPointer<click::network::AccessManager>& nam); |
681 | + const QSharedPointer<click::network::AccessManager>& nam, |
682 | + std::shared_ptr<click::DepartmentsDb> depts); |
683 | public: |
684 | struct Actions |
685 | { |
686 | @@ -82,7 +84,8 @@ |
687 | Preview(const unity::scopes::Result& result, |
688 | const unity::scopes::ActionMetadata& metadata, |
689 | const QSharedPointer<click::web::Client>& client, |
690 | - const QSharedPointer<click::network::AccessManager>& nam); |
691 | + const QSharedPointer<click::network::AccessManager>& nam, |
692 | + std::shared_ptr<click::DepartmentsDb> depts); |
693 | // From unity::scopes::PreviewQuery |
694 | void cancelled() override; |
695 | virtual void run(unity::scopes::PreviewReplyProxy const& reply) override; |
696 | @@ -140,7 +143,8 @@ |
697 | InstallingPreview(std::string const& download_url, |
698 | const unity::scopes::Result& result, |
699 | const QSharedPointer<click::web::Client>& client, |
700 | - const QSharedPointer<click::network::AccessManager>& nam); |
701 | + const QSharedPointer<click::network::AccessManager>& nam, |
702 | + std::shared_ptr<click::DepartmentsDb> depts); |
703 | |
704 | virtual ~InstallingPreview(); |
705 | |
706 | @@ -148,8 +152,10 @@ |
707 | |
708 | protected: |
709 | virtual scopes::PreviewWidgetList progressBarWidget(const std::string& object_path); |
710 | + void store_department(const PackageDetails& pkg); |
711 | std::string download_url; |
712 | QSharedPointer<click::Downloader> downloader; |
713 | + std::shared_ptr<click::DepartmentsDb> depts_db; |
714 | void startLauncherAnimation(const PackageDetails& details); |
715 | }; |
716 | |
717 | |
718 | === modified file 'libclickscope/tests/CMakeLists.txt' |
719 | --- libclickscope/tests/CMakeLists.txt 2014-06-26 17:52:31 +0000 |
720 | +++ libclickscope/tests/CMakeLists.txt 2014-07-02 12:34:49 +0000 |
721 | @@ -6,6 +6,7 @@ |
722 | SET (CMAKE_AUTOMOC ON) |
723 | |
724 | find_package(Qt5Core REQUIRED) |
725 | +find_package(Qt5Sql REQUIRED) |
726 | |
727 | include_directories ( |
728 | ${CMAKE_SOURCE_DIR}/libclickscope |
729 | @@ -15,6 +16,7 @@ |
730 | ) |
731 | |
732 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test_data.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/test_data.cpp) |
733 | +add_definitions(-DTEST_DIR="${CMAKE_CURRENT_BINARY_DIR}") |
734 | |
735 | add_executable (${LIBCLICKSCOPE_TESTS_TARGET} |
736 | mock_network_access_manager.h |
737 | @@ -31,11 +33,13 @@ |
738 | test_reviews.cpp |
739 | test_smartconnect.cpp |
740 | test_webclient.cpp |
741 | + test_departments.cpp |
742 | + test_departments-db.cpp |
743 | |
744 | ${CMAKE_CURRENT_BINARY_DIR}/test_data.cpp |
745 | ) |
746 | |
747 | -qt5_use_modules(${LIBCLICKSCOPE_TESTS_TARGET} Core) |
748 | +qt5_use_modules(${LIBCLICKSCOPE_TESTS_TARGET} Core Sql) |
749 | |
750 | target_link_libraries(${LIBCLICKSCOPE_TESTS_TARGET} |
751 | ${SCOPE_LIB_NAME} |
752 | |
753 | === added file 'libclickscope/tests/test_departments-db.cpp' |
754 | --- libclickscope/tests/test_departments-db.cpp 1970-01-01 00:00:00 +0000 |
755 | +++ libclickscope/tests/test_departments-db.cpp 2014-07-02 12:34:49 +0000 |
756 | @@ -0,0 +1,228 @@ |
757 | +/* |
758 | + * Copyright (C) 2014 Canonical Ltd. |
759 | + * |
760 | + * This program is free software: you can redistribute it and/or modify it |
761 | + * under the terms of the GNU General Public License version 3, as published |
762 | + * by the Free Software Foundation. |
763 | + * |
764 | + * This program is distributed in the hope that it will be useful, but |
765 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
766 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
767 | + * PURPOSE. See the GNU General Public License for more details. |
768 | + * |
769 | + * You should have received a copy of the GNU General Public License along |
770 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
771 | + * |
772 | + * In addition, as a special exception, the copyright holders give |
773 | + * permission to link the code of portions of this program with the |
774 | + * OpenSSL library under certain conditions as described in each |
775 | + * individual source file, and distribute linked combinations |
776 | + * including the two. |
777 | + * You must obey the GNU General Public License in all respects |
778 | + * for all of the code used other than OpenSSL. If you modify |
779 | + * file(s) with this exception, you may extend this exception to your |
780 | + * version of the file(s), but you are not obligated to do so. If you |
781 | + * do not wish to do so, delete this exception statement from your |
782 | + * version. If you delete this exception statement from all source |
783 | + * files in the program, then also delete it here. |
784 | + */ |
785 | + |
786 | +#include <gtest/gtest.h> |
787 | +#include "fake_json.h" |
788 | +#include <click/departments-db.h> |
789 | +#include <memory> |
790 | +#include <algorithm> |
791 | +#include <unistd.h> |
792 | + |
793 | +using namespace click; |
794 | + |
795 | +class DepartmentsDbTest: public ::testing::Test |
796 | +{ |
797 | +public: |
798 | + const std::string db_path = TEST_DIR "/departments-db-test.sqlite"; |
799 | + |
800 | + void SetUp() override |
801 | + { |
802 | + db.reset(new DepartmentsDb(db_path)); |
803 | + db->store_department_name("tools", "", "Tools"); |
804 | + db->store_department_name("office", "", "Office"); |
805 | + |
806 | + db->store_department_mapping("office", "tools"); |
807 | + |
808 | + db->store_package_mapping("app1", {"tools"}); |
809 | + db->store_package_mapping("app2", {"office"}); |
810 | + |
811 | + db->store_department_name("games", "", "Games"); |
812 | + db->store_department_name("games", "pl_PL", "Gry"); |
813 | + db->store_department_name("rpg", "", "RPG"); |
814 | + db->store_department_name("card", "", "Card"); |
815 | + db->store_department_name("fps", "", "First Person Shooter"); |
816 | + |
817 | + db->store_department_mapping("rpg", "games"); |
818 | + db->store_department_mapping("card", "games"); |
819 | + db->store_department_mapping("fps", "games"); |
820 | + |
821 | + db->store_package_mapping("game1", {"rpg", "fps"}); |
822 | + db->store_package_mapping("game2", {"fps"}); |
823 | + } |
824 | + |
825 | + void TearDown() override |
826 | + { |
827 | + unlink(db_path.c_str()); |
828 | + } |
829 | + |
830 | +protected: |
831 | + std::unique_ptr<DepartmentsDb> db; |
832 | +}; |
833 | + |
834 | +TEST_F(DepartmentsDbTest, testDepartmentNameLookup) |
835 | +{ |
836 | + { |
837 | + EXPECT_EQ("Games", db->get_department_name("games", {"en_EN", ""})); |
838 | + EXPECT_EQ("Gry", db->get_department_name("games", {"pl_PL", ""})); |
839 | + EXPECT_EQ("First Person Shooter", db->get_department_name("fps", {"en_EN", ""})); |
840 | + EXPECT_EQ("Office", db->get_department_name("office", {"en_EN", ""})); |
841 | + EXPECT_EQ("Tools", db->get_department_name("tools", {"en_EN", ""})); |
842 | + |
843 | + EXPECT_THROW(db->get_department_name("xyz", {"en_EN", ""}), std::logic_error); |
844 | + } |
845 | +} |
846 | + |
847 | +TEST_F(DepartmentsDbTest, testDepartmentNameUpdates) |
848 | +{ |
849 | + { |
850 | + EXPECT_EQ(7u, db->department_name_count()); |
851 | + db->store_department_name("tools", "", "Tools!"); |
852 | + EXPECT_EQ("Tools!", db->get_department_name("tools", {"en_EN", ""})); |
853 | + db->store_department_name("games", "pl_PL", "Gry!!!"); |
854 | + EXPECT_EQ("Gry!!!", db->get_department_name("games", {"pl_PL"})); |
855 | + EXPECT_EQ(7u, db->department_name_count()); |
856 | + } |
857 | +} |
858 | + |
859 | +TEST_F(DepartmentsDbTest, testDepartmentParentLookup) |
860 | +{ |
861 | + { |
862 | + EXPECT_EQ("games", db->get_parent_department_id("rpg")); |
863 | + EXPECT_EQ("games", db->get_parent_department_id("card")); |
864 | + EXPECT_EQ("", db->get_parent_department_id("games")); |
865 | + |
866 | + EXPECT_EQ("tools", db->get_parent_department_id("office")); |
867 | + EXPECT_EQ("", db->get_parent_department_id("tools")); |
868 | + |
869 | + EXPECT_THROW(db->get_parent_department_id("xyz"), std::logic_error); |
870 | + } |
871 | +} |
872 | + |
873 | +TEST_F(DepartmentsDbTest, testDepartmentChildrenLookup) |
874 | +{ |
875 | + { |
876 | + EXPECT_EQ(0, db->get_children_departments("xyz").size()); |
877 | + } |
878 | + { |
879 | + auto depts = db->get_children_departments(""); |
880 | + EXPECT_EQ(2u, depts.size()); |
881 | + EXPECT_TRUE(std::find(depts.begin(), depts.end(), DepartmentsDb::DepartmentInfo("tools", true)) != depts.end()); |
882 | + EXPECT_TRUE(std::find(depts.begin(), depts.end(), DepartmentsDb::DepartmentInfo("games", true)) != depts.end()); |
883 | + } |
884 | + { |
885 | + auto depts = db->get_children_departments("tools"); |
886 | + EXPECT_EQ(1u, depts.size()); |
887 | + EXPECT_TRUE(std::find(depts.begin(), depts.end(), DepartmentsDb::DepartmentInfo("office", false)) != depts.end()); |
888 | + } |
889 | + { |
890 | + auto depts = db->get_children_departments("games"); |
891 | + EXPECT_EQ(3u, depts.size()); |
892 | + EXPECT_TRUE(std::find(depts.begin(), depts.end(), DepartmentsDb::DepartmentInfo("rpg", false)) != depts.end()); |
893 | + EXPECT_TRUE(std::find(depts.begin(), depts.end(), DepartmentsDb::DepartmentInfo("fps", false)) != depts.end()); |
894 | + EXPECT_TRUE(std::find(depts.begin(), depts.end(), DepartmentsDb::DepartmentInfo("card", false)) != depts.end()); |
895 | + } |
896 | +} |
897 | + |
898 | +TEST_F(DepartmentsDbTest, testPackageLookup) |
899 | +{ |
900 | + { |
901 | + auto pkgs = db->get_packages_for_department("rpg", false); |
902 | + EXPECT_EQ(1u, pkgs.size()); |
903 | + EXPECT_TRUE(pkgs.find("game1") != pkgs.end()); |
904 | + } |
905 | + { |
906 | + auto pkgs = db->get_packages_for_department("fps", false); |
907 | + EXPECT_EQ(2u, pkgs.size()); |
908 | + EXPECT_TRUE(pkgs.find("game1") != pkgs.end()); |
909 | + EXPECT_TRUE(pkgs.find("game2") != pkgs.end()); |
910 | + } |
911 | + { |
912 | + auto pkgs = db->get_packages_for_department("card", false); |
913 | + EXPECT_EQ(0, pkgs.size()); |
914 | + } |
915 | +} |
916 | + |
917 | +TEST_F(DepartmentsDbTest, testRecursivePackageLookup) |
918 | +{ |
919 | + { |
920 | + // get packages from subdepartments of games department |
921 | + auto pkgs = db->get_packages_for_department("games", true); |
922 | + EXPECT_EQ(2u, pkgs.size()); |
923 | + EXPECT_TRUE(pkgs.find("game1") != pkgs.end()); |
924 | + EXPECT_TRUE(pkgs.find("game2") != pkgs.end()); |
925 | + } |
926 | + { |
927 | + // rpg has no subdepartments, so we just get the packages of rpg department |
928 | + auto pkgs = db->get_packages_for_department("rpg", true); |
929 | + EXPECT_EQ(1u, pkgs.size()); |
930 | + EXPECT_TRUE(pkgs.find("game1") != pkgs.end()); |
931 | + } |
932 | + { |
933 | + auto pkgs = db->get_packages_for_department("card", true); |
934 | + EXPECT_EQ(0, pkgs.size()); |
935 | + } |
936 | +} |
937 | + |
938 | +TEST_F(DepartmentsDbTest, testPackageUpdates) |
939 | +{ |
940 | + auto pkgs = db->get_packages_for_department("fps"); |
941 | + EXPECT_EQ(2, pkgs.size()); |
942 | + EXPECT_TRUE(pkgs.find("game2") != pkgs.end()); |
943 | + |
944 | + // game2 gets moved to card and removed from fps; game1 still in fps |
945 | + db->store_package_mapping("game2", {"card"}); |
946 | + |
947 | + pkgs = db->get_packages_for_department("fps", false); |
948 | + EXPECT_EQ(1, pkgs.size()); |
949 | + EXPECT_TRUE(pkgs.find("game2") == pkgs.end()); |
950 | + pkgs = db->get_packages_for_department("card", false); |
951 | + EXPECT_EQ(1, pkgs.size()); |
952 | + EXPECT_TRUE(pkgs.find("game2") != pkgs.end()); |
953 | +} |
954 | + |
955 | +TEST_F(DepartmentsDbTest, testInvalidDepartments) |
956 | +{ |
957 | + EXPECT_THROW(db->get_parent_department_id(""), std::logic_error); |
958 | + EXPECT_THROW(db->get_parent_department_id("foooo"), std::logic_error); |
959 | +} |
960 | + |
961 | +TEST_F(DepartmentsDbTest, testEmptyArguments) |
962 | +{ |
963 | + EXPECT_THROW(db->store_department_name("", "", "Foo"), std::logic_error); |
964 | + EXPECT_THROW(db->store_department_name("foo", "", ""), std::logic_error); |
965 | + EXPECT_THROW(db->store_department_mapping("", "foo"), std::logic_error); |
966 | + EXPECT_THROW(db->store_department_mapping("foo", ""), std::logic_error); |
967 | + EXPECT_THROW(db->store_package_mapping("", {"foo"}), std::logic_error); |
968 | + EXPECT_THROW(db->store_package_mapping("foo", {}), std::logic_error); |
969 | + EXPECT_THROW(db->store_package_mapping("foo", {""}), std::logic_error); |
970 | +} |
971 | + |
972 | +TEST_F(DepartmentsDbTest, testNoDuplicates) |
973 | +{ |
974 | + db->store_package_mapping("game2", {"fps"}); |
975 | + db->store_package_mapping("game2", {"fps"}); |
976 | + db->store_department_name("games", "pl_PL", "Gry"); |
977 | + db->store_department_name("games", "pl_PL", "Gry"); |
978 | + db->store_department_mapping("office", "tools"); |
979 | + db->store_department_mapping("office", "tools"); |
980 | + |
981 | + EXPECT_EQ(7u, db->department_name_count()); |
982 | + EXPECT_EQ(5u, db->package_count()); |
983 | +} |
984 | + |
985 | |
986 | === modified file 'libclickscope/tests/test_index.cpp' |
987 | --- libclickscope/tests/test_index.cpp 2014-06-26 18:57:08 +0000 |
988 | +++ libclickscope/tests/test_index.cpp 2014-07-02 12:34:49 +0000 |
989 | @@ -342,7 +342,8 @@ |
990 | {"sshot1", "sshot2"}, |
991 | 177582, |
992 | "0.2", |
993 | - "None" |
994 | + "None", |
995 | + "tools" |
996 | }; |
997 | EXPECT_CALL(*this, details_callback(fake_details, _)).Times(1); |
998 | response->replyFinished(); |
999 | @@ -389,7 +390,8 @@ |
1000 | {"sshot1", "sshot2"}, |
1001 | 177582, |
1002 | "0.2", |
1003 | - "None" |
1004 | + "None", |
1005 | + "tools" |
1006 | }; |
1007 | |
1008 | EXPECT_CALL(*this, details_callback(fake_details, _)).Times(1); |
1009 | |
1010 | === modified file 'scope/clickapps/CMakeLists.txt' |
1011 | --- scope/clickapps/CMakeLists.txt 2014-06-04 14:45:48 +0000 |
1012 | +++ scope/clickapps/CMakeLists.txt 2014-07-02 12:34:49 +0000 |
1013 | @@ -1,6 +1,7 @@ |
1014 | SET (CMAKE_INCLUDE_CURRENT_DIR ON) |
1015 | SET (CMAKE_AUTOMOC ON) |
1016 | find_package (Qt5Core REQUIRED) |
1017 | +find_package (Qt5Sql REQUIRED) |
1018 | pkg_check_modules(JSON_CPP REQUIRED jsoncpp) |
1019 | |
1020 | add_definitions( |
1021 | @@ -20,7 +21,7 @@ |
1022 | ${JSON_CPP_INCLUDE_DIRS} |
1023 | ) |
1024 | |
1025 | -qt5_use_modules (${APPS_LIB_UNVERSIONED} Network) |
1026 | +qt5_use_modules (${APPS_LIB_UNVERSIONED} Network Sql) |
1027 | |
1028 | target_link_libraries (${APPS_LIB_UNVERSIONED} |
1029 | ${SCOPE_LIB_NAME} |
1030 | |
1031 | === modified file 'scope/clickapps/apps-query.cpp' |
1032 | --- scope/clickapps/apps-query.cpp 2014-06-30 20:06:33 +0000 |
1033 | +++ scope/clickapps/apps-query.cpp 2014-07-02 12:34:49 +0000 |
1034 | @@ -29,6 +29,7 @@ |
1035 | |
1036 | #include <click/application.h> |
1037 | #include <click/interface.h> |
1038 | +#include <click/departments-db.h> |
1039 | |
1040 | #include <click/key_file_locator.h> |
1041 | |
1042 | @@ -37,6 +38,7 @@ |
1043 | #include <unity/scopes/CannedQuery.h> |
1044 | #include <unity/scopes/SearchReply.h> |
1045 | #include <unity/scopes/SearchMetadata.h> |
1046 | +#include <unity/scopes/Department.h> |
1047 | |
1048 | #include <vector> |
1049 | |
1050 | @@ -128,18 +130,21 @@ |
1051 | |
1052 | struct click::Query::Private |
1053 | { |
1054 | - Private(click::Index& index, const scopes::SearchMetadata& metadata) |
1055 | + Private(click::Index& index, std::shared_ptr<click::DepartmentsDb> depts_db, const scopes::SearchMetadata& metadata) |
1056 | : index(index), |
1057 | + depts_db(depts_db), |
1058 | meta(metadata) |
1059 | { |
1060 | } |
1061 | click::Index& index; |
1062 | + std::shared_ptr<click::DepartmentsDb> depts_db; |
1063 | scopes::SearchMetadata meta; |
1064 | }; |
1065 | |
1066 | -click::Query::Query(unity::scopes::CannedQuery const& query, click::Index& index, scopes::SearchMetadata const& metadata) |
1067 | +click::Query::Query(unity::scopes::CannedQuery const& query, click::Index& index, std::shared_ptr<DepartmentsDb> depts_db, |
1068 | + scopes::SearchMetadata const& metadata) |
1069 | : unity::scopes::SearchQueryBase(query, metadata), |
1070 | - impl(new Private(index, metadata)) |
1071 | + impl(new Private(index, depts_db, metadata)) |
1072 | { |
1073 | } |
1074 | |
1075 | @@ -194,15 +199,85 @@ |
1076 | } |
1077 | } |
1078 | |
1079 | +void click::Query::push_local_departments(scopes::SearchReplyProxy const& replyProxy) |
1080 | +{ |
1081 | + auto const current_dep_id = query().department_id(); |
1082 | + const std::list<std::string> locales = { search_metadata().locale(), "en_US", "" }; |
1083 | + |
1084 | + unity::scopes::Department::SPtr root; |
1085 | + |
1086 | + try |
1087 | + { |
1088 | + static const std::string all_dept_name = _("All departments"); |
1089 | + |
1090 | + // create node for current department |
1091 | + auto name = current_dep_id == "" ? all_dept_name : impl->depts_db->get_department_name(current_dep_id, locales); |
1092 | + unity::scopes::Department::SPtr current = unity::scopes::Department::create(current_dep_id, query(), name); |
1093 | + |
1094 | + // attach subdepartments to it |
1095 | + for (auto const& subdep: impl->depts_db->get_children_departments(current_dep_id)) |
1096 | + { |
1097 | + name = impl->depts_db->get_department_name(subdep.id, locales); |
1098 | + unity::scopes::Department::SPtr dep = unity::scopes::Department::create(subdep.id, query(), name); |
1099 | + dep->set_has_subdepartments(subdep.has_children); |
1100 | + current->add_subdepartment(dep); |
1101 | + } |
1102 | + |
1103 | + // if current is not the top, then gets its parent |
1104 | + if (current_dep_id != "") |
1105 | + { |
1106 | + auto const parent_dep_id = impl->depts_db->get_parent_department_id(current_dep_id); |
1107 | + root = unity::scopes::Department::create(parent_dep_id, query(), parent_dep_id == "" ? all_dept_name : |
1108 | + impl->depts_db->get_department_name(parent_dep_id, locales)); |
1109 | + root->add_subdepartment(current); |
1110 | + } |
1111 | + else |
1112 | + { |
1113 | + root = current; |
1114 | + } |
1115 | + |
1116 | + replyProxy->register_departments(root); |
1117 | + } |
1118 | + catch (const std::exception& e) |
1119 | + { |
1120 | + qWarning() << "Failed to push departments: " << QString::fromStdString(e.what()); |
1121 | + } |
1122 | +} |
1123 | + |
1124 | void click::Query::run(scopes::SearchReplyProxy const& searchReply) |
1125 | { |
1126 | - auto querystr = query().query_string(); |
1127 | + auto const querystr = query().query_string(); |
1128 | + auto const current_dept = query().department_id(); |
1129 | + |
1130 | std::string categoryTemplate = CATEGORY_APPS_SEARCH; |
1131 | if (querystr.empty()) { |
1132 | categoryTemplate = CATEGORY_APPS_DISPLAY; |
1133 | - } |
1134 | - auto localResults = clickInterfaceInstance().find_installed_apps( |
1135 | - querystr); |
1136 | + if (impl->depts_db) |
1137 | + { |
1138 | + push_local_departments(searchReply); |
1139 | + } |
1140 | + } |
1141 | + |
1142 | + // |
1143 | + // get the set of packages that belong to current deparment; |
1144 | + // only apply department filtering if not in root of all departments. |
1145 | + bool apply_department_filter = (querystr.empty() && !current_dept.empty()); |
1146 | + std::unordered_set<std::string> pkgs_in_department; |
1147 | + if (impl->depts_db && apply_department_filter) |
1148 | + { |
1149 | + try |
1150 | + { |
1151 | + pkgs_in_department = impl->depts_db->get_packages_for_department(current_dept); |
1152 | + } |
1153 | + catch (const std::exception& e) |
1154 | + { |
1155 | + qWarning() << "Failed to get packages of department" << QString::fromStdString(current_dept); |
1156 | + apply_department_filter = false; // disable so that we are not loosing any apps if something goes wrong |
1157 | + } |
1158 | + } |
1159 | + |
1160 | + auto const localResults = clickInterfaceInstance().find_installed_apps( |
1161 | + querystr, pkgs_in_department, apply_department_filter); |
1162 | |
1163 | push_local_results( |
1164 | searchReply, |
1165 | |
1166 | === modified file 'scope/clickapps/apps-query.h' |
1167 | --- scope/clickapps/apps-query.h 2014-05-28 14:27:28 +0000 |
1168 | +++ scope/clickapps/apps-query.h 2014-07-02 12:34:49 +0000 |
1169 | @@ -44,6 +44,7 @@ |
1170 | |
1171 | class Application; |
1172 | class Index; |
1173 | +class DepartmentsDb; |
1174 | |
1175 | class Query : public scopes::SearchQueryBase |
1176 | { |
1177 | @@ -60,7 +61,7 @@ |
1178 | constexpr static const char* VERSION{"version"}; |
1179 | }; |
1180 | |
1181 | - Query(unity::scopes::CannedQuery const& query, click::Index& index, scopes::SearchMetadata const& metadata); |
1182 | + Query(unity::scopes::CannedQuery const& query, click::Index& index, std::shared_ptr<DepartmentsDb> depts_db, scopes::SearchMetadata const& metadata); |
1183 | virtual ~Query(); |
1184 | |
1185 | virtual void cancelled() override; |
1186 | @@ -72,6 +73,7 @@ |
1187 | virtual void push_local_results(scopes::SearchReplyProxy const &replyProxy, |
1188 | std::vector<click::Application> const &apps, |
1189 | std::string& categoryTemplate); |
1190 | + virtual void push_local_departments(scopes::SearchReplyProxy const& replyProxy); |
1191 | |
1192 | private: |
1193 | struct Private; |
1194 | |
1195 | === modified file 'scope/clickapps/apps-scope.cpp' |
1196 | --- scope/clickapps/apps-scope.cpp 2014-06-18 16:23:50 +0000 |
1197 | +++ scope/clickapps/apps-scope.cpp 2014-07-02 12:34:49 +0000 |
1198 | @@ -31,6 +31,7 @@ |
1199 | #include <click/preview.h> |
1200 | #include <click/interface.h> |
1201 | #include <click/scope_activation.h> |
1202 | +#include <click/departments-db.h> |
1203 | |
1204 | #include <QSharedPointer> |
1205 | |
1206 | @@ -48,6 +49,14 @@ |
1207 | nam.reset(new click::network::AccessManager()); |
1208 | client.reset(new click::web::Client(nam)); |
1209 | index.reset(new click::Index(client)); |
1210 | + try |
1211 | + { |
1212 | + depts_db = click::DepartmentsDb::create_db(); |
1213 | + } |
1214 | + catch (const std::runtime_error& e) |
1215 | + { |
1216 | + std::cerr << "Failed to get cache directory" << std::endl; |
1217 | + } |
1218 | } |
1219 | |
1220 | click::Scope::~Scope() |
1221 | @@ -78,14 +87,14 @@ |
1222 | |
1223 | scopes::SearchQueryBase::UPtr click::Scope::search(unity::scopes::CannedQuery const& q, scopes::SearchMetadata const& metadata) |
1224 | { |
1225 | - return scopes::SearchQueryBase::UPtr(new click::Query(q, *index, metadata)); |
1226 | + return scopes::SearchQueryBase::UPtr(new click::Query(q, *index, depts_db, metadata)); |
1227 | } |
1228 | |
1229 | |
1230 | unity::scopes::PreviewQueryBase::UPtr click::Scope::preview(const unity::scopes::Result& result, |
1231 | const unity::scopes::ActionMetadata& metadata) { |
1232 | qDebug() << "Scope::preview() called."; |
1233 | - return scopes::PreviewQueryBase::UPtr{new click::Preview(result, metadata, client, nam)}; |
1234 | + return scopes::PreviewQueryBase::UPtr{new click::Preview(result, metadata, client, nam, depts_db)}; |
1235 | } |
1236 | |
1237 | |
1238 | |
1239 | === modified file 'scope/clickapps/apps-scope.h' |
1240 | --- scope/clickapps/apps-scope.h 2014-06-18 14:42:47 +0000 |
1241 | +++ scope/clickapps/apps-scope.h 2014-07-02 12:34:49 +0000 |
1242 | @@ -43,6 +43,9 @@ |
1243 | |
1244 | namespace click |
1245 | { |
1246 | + |
1247 | +class DepartmentsDb; |
1248 | + |
1249 | class Scope : public scopes::ScopeBase |
1250 | { |
1251 | public: |
1252 | @@ -64,6 +67,7 @@ |
1253 | QSharedPointer<click::network::AccessManager> nam; |
1254 | QSharedPointer<click::web::Client> client; |
1255 | QSharedPointer<click::Index> index; |
1256 | + std::shared_ptr<click::DepartmentsDb> depts_db; |
1257 | |
1258 | std::string installApplication(unity::scopes::Result const& result); |
1259 | }; |
1260 | |
1261 | === modified file 'scope/clickstore/CMakeLists.txt' |
1262 | --- scope/clickstore/CMakeLists.txt 2014-06-23 15:00:28 +0000 |
1263 | +++ scope/clickstore/CMakeLists.txt 2014-07-02 12:34:49 +0000 |
1264 | @@ -1,6 +1,7 @@ |
1265 | SET (CMAKE_INCLUDE_CURRENT_DIR ON) |
1266 | SET (CMAKE_AUTOMOC ON) |
1267 | find_package (Qt5Core REQUIRED) |
1268 | +find_package (Qt5Sql REQUIRED) |
1269 | pkg_check_modules(JSON_CPP REQUIRED jsoncpp) |
1270 | |
1271 | add_definitions( |
1272 | @@ -19,7 +20,7 @@ |
1273 | ${JSON_CPP_INCLUDE_DIRS} |
1274 | ) |
1275 | |
1276 | -qt5_use_modules (${STORE_LIB_UNVERSIONED} Network) |
1277 | +qt5_use_modules (${STORE_LIB_UNVERSIONED} Network Sql) |
1278 | |
1279 | target_link_libraries (${STORE_LIB_UNVERSIONED} |
1280 | ${SCOPE_LIB_NAME} |
1281 | |
1282 | === modified file 'scope/clickstore/store-query.cpp' |
1283 | --- scope/clickstore/store-query.cpp 2014-06-26 18:07:51 +0000 |
1284 | +++ scope/clickstore/store-query.cpp 2014-07-02 12:34:49 +0000 |
1285 | @@ -32,6 +32,7 @@ |
1286 | #include "store-query.h" |
1287 | #include "store-scope.h" |
1288 | #include <click/qtbridge.h> |
1289 | +#include <click/departments-db.h> |
1290 | |
1291 | #include <click/key_file_locator.h> |
1292 | |
1293 | @@ -96,25 +97,29 @@ |
1294 | struct click::Query::Private |
1295 | { |
1296 | Private(click::Index& index, click::DepartmentLookup& depts, |
1297 | + std::shared_ptr<click::DepartmentsDb> depts_db, |
1298 | click::HighlightList& highlights, const scopes::SearchMetadata& metadata) |
1299 | : index(index), |
1300 | department_lookup(depts), |
1301 | + depts_db(depts_db), |
1302 | highlights(highlights), |
1303 | meta(metadata) |
1304 | { |
1305 | } |
1306 | click::Index& index; |
1307 | click::DepartmentLookup& department_lookup; |
1308 | + std::shared_ptr<click::DepartmentsDb> depts_db; |
1309 | click::HighlightList& highlights; |
1310 | scopes::SearchMetadata meta; |
1311 | click::web::Cancellable search_operation; |
1312 | }; |
1313 | |
1314 | click::Query::Query(unity::scopes::CannedQuery const& query, click::Index& index, click::DepartmentLookup& depts, |
1315 | + std::shared_ptr<click::DepartmentsDb> depts_db, |
1316 | click::HighlightList& highlights, |
1317 | scopes::SearchMetadata const& metadata) |
1318 | : unity::scopes::SearchQueryBase(query, metadata), |
1319 | - impl(new Private(index, depts, highlights, metadata)) |
1320 | + impl(new Private(index, depts, depts_db, highlights, metadata)) |
1321 | { |
1322 | } |
1323 | |
1324 | @@ -216,6 +221,30 @@ |
1325 | root->set_subdepartments(departments); |
1326 | } |
1327 | |
1328 | +// recursively store all departments in the departments database |
1329 | +void click::Query::store_departments(const click::DepartmentList& depts) |
1330 | +{ |
1331 | + assert(impl->depts_db); |
1332 | + |
1333 | + qDebug() << "Storing departments in the database"; |
1334 | + try |
1335 | + { |
1336 | + for (auto const& dept: depts) |
1337 | + { |
1338 | + impl->depts_db->store_department_name(dept->id(), impl->meta.locale(), dept->name()); |
1339 | + for (auto const& subdep: dept->sub_departments()) |
1340 | + { |
1341 | + impl->depts_db->store_department_mapping(subdep->id(), dept->id()); |
1342 | + } |
1343 | + store_departments(dept->sub_departments()); |
1344 | + } |
1345 | + } |
1346 | + catch (const std::exception &e) |
1347 | + { |
1348 | + qWarning() << "Failed to update database: " << QString::fromStdString(e.what()); |
1349 | + } |
1350 | +} |
1351 | + |
1352 | void click::Query::push_package(const scopes::SearchReplyProxy& searchReply, scopes::Category::SCPtr category, const PackageSet &installedPackages, const Package& pkg) |
1353 | { |
1354 | qDebug() << "pushing result" << QString::fromStdString(pkg.name); |
1355 | @@ -371,6 +400,15 @@ |
1356 | impl->department_lookup.rebuild(rdeps); |
1357 | impl->highlights = highlights; |
1358 | qDebug() << "Total number of departments:" << impl->department_lookup.size() << ", highlights:" << highlights.size(); |
1359 | + |
1360 | + if (impl->depts_db) |
1361 | + { |
1362 | + store_departments(deps); |
1363 | + } |
1364 | + else |
1365 | + { |
1366 | + qWarning() << "Departments db not available"; |
1367 | + } |
1368 | } |
1369 | else |
1370 | { |
1371 | |
1372 | === modified file 'scope/clickstore/store-query.h' |
1373 | --- scope/clickstore/store-query.h 2014-06-18 09:01:20 +0000 |
1374 | +++ scope/clickstore/store-query.h 2014-07-02 12:34:49 +0000 |
1375 | @@ -50,6 +50,7 @@ |
1376 | class Application; |
1377 | class Index; |
1378 | class DepartmentLookup; |
1379 | +class DepartmentsDb; |
1380 | |
1381 | class Query : public scopes::SearchQueryBase |
1382 | { |
1383 | @@ -76,7 +77,7 @@ |
1384 | constexpr static const char* VERSION{"version"}; |
1385 | }; |
1386 | |
1387 | - Query(unity::scopes::CannedQuery const& query, click::Index& index, click::DepartmentLookup& dept_lookup, click::HighlightList& highlights, |
1388 | + Query(unity::scopes::CannedQuery const& query, click::Index& index, click::DepartmentLookup& dept_lookup, std::shared_ptr<click::DepartmentsDb> depts_db, click::HighlightList& highlights, |
1389 | scopes::SearchMetadata const& metadata); |
1390 | virtual ~Query(); |
1391 | |
1392 | @@ -86,6 +87,7 @@ |
1393 | |
1394 | protected: |
1395 | virtual void populate_departments(const click::DepartmentList& depts, const std::string& current_department_id, unity::scopes::Department::SPtr &root); |
1396 | + virtual void store_departments(const click::DepartmentList& depts); |
1397 | virtual void push_departments(const scopes::SearchReplyProxy& searchReply, const scopes::Department::SCPtr& root); |
1398 | virtual void add_highlights(scopes::SearchReplyProxy const& searchReply, const PackageSet& installedPackages); |
1399 | virtual void add_available_apps(const scopes::SearchReplyProxy &searchReply, const PackageSet &installedPackages, const std::string &category); |
1400 | |
1401 | === modified file 'scope/clickstore/store-scope.cpp' |
1402 | --- scope/clickstore/store-scope.cpp 2014-06-23 15:00:28 +0000 |
1403 | +++ scope/clickstore/store-scope.cpp 2014-07-02 12:34:49 +0000 |
1404 | @@ -28,6 +28,7 @@ |
1405 | */ |
1406 | |
1407 | #include <click/qtbridge.h> |
1408 | +#include <click/departments-db.h> |
1409 | #include <click/department-lookup.h> |
1410 | #include "store-scope.h" |
1411 | #include "store-query.h" |
1412 | @@ -42,6 +43,7 @@ |
1413 | #include <click/click-i18n.h> |
1414 | |
1415 | #include <logging.h> |
1416 | +#include <iostream> |
1417 | |
1418 | bool click::Scope::old_api = false; |
1419 | |
1420 | @@ -52,6 +54,14 @@ |
1421 | index.reset(new click::Index(client)); |
1422 | depts.reset(new click::DepartmentLookup()); |
1423 | highlights.reset(new click::HighlightList()); |
1424 | + try |
1425 | + { |
1426 | + depts_db = click::DepartmentsDb::create_db(); |
1427 | + } |
1428 | + catch (const std::runtime_error& e) |
1429 | + { |
1430 | + std::cerr << "Failed to get cache directory" << std::endl; |
1431 | + } |
1432 | } |
1433 | |
1434 | click::Scope::~Scope() |
1435 | @@ -94,14 +104,14 @@ |
1436 | |
1437 | scopes::SearchQueryBase::UPtr click::Scope::search(unity::scopes::CannedQuery const& q, scopes::SearchMetadata const& metadata) |
1438 | { |
1439 | - return scopes::SearchQueryBase::UPtr(new click::Query(q, *index, *depts, *highlights, metadata)); |
1440 | + return scopes::SearchQueryBase::UPtr(new click::Query(q, *index, *depts, depts_db, *highlights, metadata)); |
1441 | } |
1442 | |
1443 | |
1444 | unity::scopes::PreviewQueryBase::UPtr click::Scope::preview(const unity::scopes::Result& result, |
1445 | const unity::scopes::ActionMetadata& metadata) { |
1446 | qDebug() << "Scope::preview() called."; |
1447 | - return scopes::PreviewQueryBase::UPtr{new click::Preview(result, metadata, client, nam)}; |
1448 | + return scopes::PreviewQueryBase::UPtr{new click::Preview(result, metadata, client, nam, depts_db)}; |
1449 | } |
1450 | |
1451 | unity::scopes::ActivationQueryBase::UPtr click::Scope::perform_action(unity::scopes::Result const& result, unity::scopes::ActionMetadata const& metadata, |
1452 | |
1453 | === modified file 'scope/clickstore/store-scope.h' |
1454 | --- scope/clickstore/store-scope.h 2014-06-18 18:07:39 +0000 |
1455 | +++ scope/clickstore/store-scope.h 2014-07-02 12:34:49 +0000 |
1456 | @@ -46,6 +46,7 @@ |
1457 | { |
1458 | |
1459 | class DepartmentLookup; |
1460 | +class DepartmentsDb; |
1461 | |
1462 | class Scope : public scopes::ScopeBase |
1463 | { |
1464 | @@ -73,6 +74,7 @@ |
1465 | QSharedPointer<click::Index> index; |
1466 | std::shared_ptr<click::DepartmentLookup> depts; |
1467 | std::shared_ptr<click::HighlightList> highlights; |
1468 | + std::shared_ptr<click::DepartmentsDb> depts_db; |
1469 | |
1470 | std::string installApplication(unity::scopes::Result const& result); |
1471 | static bool old_api; |
1472 | |
1473 | === modified file 'scope/tests/test_query.cpp' |
1474 | --- scope/tests/test_query.cpp 2014-06-24 17:18:53 +0000 |
1475 | +++ scope/tests/test_query.cpp 2014-07-02 12:34:49 +0000 |
1476 | @@ -98,8 +98,9 @@ |
1477 | public: |
1478 | MockQueryBase(const unity::scopes::CannedQuery& query, click::Index& index, |
1479 | click::DepartmentLookup& depts, |
1480 | + std::shared_ptr<click::DepartmentsDb> depts_db, |
1481 | click::HighlightList& highlights, |
1482 | - scopes::SearchMetadata const& metadata) : click::Query(query, index, depts, highlights, metadata) |
1483 | + scopes::SearchMetadata const& metadata) : click::Query(query, index, depts, depts_db, highlights, metadata) |
1484 | { |
1485 | |
1486 | } |
1487 | @@ -115,7 +116,7 @@ |
1488 | MockQuery(const unity::scopes::CannedQuery& query, click::Index& index, |
1489 | click::DepartmentLookup& depts, |
1490 | click::HighlightList& highlights, |
1491 | - scopes::SearchMetadata const& metadata) : MockQueryBase(query, index, depts, highlights, metadata) |
1492 | + scopes::SearchMetadata const& metadata) : MockQueryBase(query, index, depts, nullptr, highlights, metadata) |
1493 | { |
1494 | |
1495 | } |
1496 | @@ -140,8 +141,8 @@ |
1497 | public: |
1498 | MockQueryRun(const unity::scopes::CannedQuery& query, click::Index& index, |
1499 | click::DepartmentLookup& depts, |
1500 | - click::HighlightList& highlights, |
1501 | - scopes::SearchMetadata const& metadata) : MockQueryBase(query, index, depts, highlights, metadata) |
1502 | + click::HighlightList& highlights, |
1503 | + scopes::SearchMetadata const& metadata) : MockQueryBase(query, index, depts, nullptr, highlights, metadata) |
1504 | { |
1505 | |
1506 | } |
Great work pawel!
I know the branch is in progress, so let me give an initial observation: in order for the branch to be more easily reviewable, and to make sure that it does not grow much more, please split it in a few branches.
The first one should only include all the methods that do the queries and the db access, and all the corresponding tests.
The second one should start filling the db from preview.cpp using the branch above.
The third one would query the db to build the combo of departments.