Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* global
2 sendAsyncMessage,
3 addMessageListener,
4 indexedDB
5 */
6 "use strict";
8 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
10 let imports = {};
12 Cu.import("resource://gre/modules/ContactDB.jsm", imports);
13 Cu.import("resource://gre/modules/ContactService.jsm", imports);
14 Cu.import("resource://gre/modules/Promise.jsm", imports);
15 Cu.importGlobalProperties(["indexedDB"]);
17 const {
18 STORE_NAME,
19 SAVED_GETALL_STORE_NAME,
20 REVISION_STORE,
21 DB_NAME,
22 ContactService,
23 } = imports;
24 // |const| will not work because
25 // it will make the Promise object immutable before assigning.
26 // Using Object.defineProperty() instead.
27 Object.defineProperty(this, "Promise", {
28 value: imports.Promise, writable: false, configurable: false
29 });
31 let DEBUG = false;
32 function debug(str) {
33 if (DEBUG){
34 dump("-*- TestMigrationChromeScript: " + str + "\n");
35 }
36 }
38 const DATA = {
39 12: {
40 SCHEMA: function createSchema12(db, transaction) {
41 let objectStore = db.createObjectStore(STORE_NAME, {keyPath: "id"});
42 objectStore.createIndex("familyName", "properties.familyName", { multiEntry: true });
43 objectStore.createIndex("givenName", "properties.givenName", { multiEntry: true });
44 objectStore.createIndex("familyNameLowerCase", "search.familyName", { multiEntry: true });
45 objectStore.createIndex("givenNameLowerCase", "search.givenName", { multiEntry: true });
46 objectStore.createIndex("telLowerCase", "search.tel", { multiEntry: true });
47 objectStore.createIndex("emailLowerCase", "search.email", { multiEntry: true });
48 objectStore.createIndex("tel", "search.exactTel", { multiEntry: true });
49 objectStore.createIndex("category", "properties.category", { multiEntry: true });
50 objectStore.createIndex("email", "search.email", { multiEntry: true });
51 objectStore.createIndex("telMatch", "search.parsedTel", {multiEntry: true});
52 db.createObjectStore(SAVED_GETALL_STORE_NAME);
53 db.createObjectStore(REVISION_STORE).put(0, "revision");
54 },
55 BAD: [
56 {
57 // this contact is bad because its "name" property is not an array and
58 // is the empty string (upgrade 16 to 17)
59 "properties": {
60 "name": "",
61 "email": [],
62 "url": [{
63 "type": ["source"],
64 "value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654"
65 }],
66 "category": ["gmail"],
67 "adr": [],
68 "tel": [{
69 "type": ["mobile"],
70 "value": "+7 123 456-78-90"
71 }],
72 "sex": "undefined",
73 "genderIdentity": "undefined"
74 },
75 "search": {
76 "givenName": [],
77 "familyName": [],
78 "email": [],
79 "category": ["gmail"],
80 "tel": ["+71234567890","71234567890","1234567890","234567890","34567890",
81 "4567890","567890","67890","7890","890","90","0","81234567890"],
82 "exactTel": ["+71234567890"],
83 "parsedTel": ["+71234567890","1234567890","81234567890","34567890"]
84 },
85 "updated": new Date("2013-07-27T16:47:40.974Z"),
86 "published": new Date("2013-07-27T16:47:40.974Z"),
87 "id": "bad-1"
88 },
89 {
90 // This contact is bad because its "name" property is not an array
91 // (upgrade 14 to 15)
92 "properties": {
93 "name": "name-bad-2",
94 "email": [],
95 "url": [{
96 "type": ["source"],
97 "value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654"
98 }],
99 "category": ["gmail"],
100 "adr": [],
101 "tel": [{
102 "type": ["mobile"],
103 "value": "+7 123 456-78-90"
104 }],
105 "sex": "undefined",
106 "genderIdentity": "undefined"
107 },
108 "search": {
109 "givenName": [],
110 "familyName": [],
111 "email": [],
112 "category": ["gmail"],
113 "tel": ["+71234567890","71234567890","1234567890","234567890","34567890",
114 "4567890","567890","67890","7890","890","90","0","81234567890"],
115 "exactTel": ["+71234567890"],
116 "parsedTel": ["+71234567890","1234567890","81234567890","34567890"]
117 },
118 "updated": new Date("2013-07-27T16:47:40.974Z"),
119 "published": new Date("2013-07-27T16:47:40.974Z"),
120 "id": "bad-2"
121 },
122 {
123 // This contact is bad because its bday property is a String (upgrade 15
124 // to 16), and its anniversary property is an empty string (upgrade 16
125 // to 17)
126 "properties": {
127 "name": ["name-bad-3"],
128 "email": [],
129 "url": [{
130 "type": ["source"],
131 "value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654"
132 }],
133 "category": ["gmail"],
134 "adr": [],
135 "tel": [{
136 "type": ["mobile"],
137 "value": "+7 123 456-78-90"
138 }],
139 "sex": "undefined",
140 "genderIdentity": "undefined",
141 "bday": "2013-07-27T16:47:40.974Z",
142 "anniversary": ""
143 },
144 "search": {
145 "givenName": [],
146 "familyName": [],
147 "email": [],
148 "category": ["gmail"],
149 "tel": ["+71234567890","71234567890","1234567890","234567890","34567890",
150 "4567890","567890","67890","7890","890","90","0","81234567890"],
151 "exactTel": ["+71234567890"],
152 "parsedTel": ["+71234567890","1234567890","81234567890","34567890"]
153 },
154 "updated": new Date("2013-07-27T16:47:40.974Z"),
155 "published": new Date("2013-07-27T16:47:40.974Z"),
156 "id": "bad-3"
157 },
158 {
159 // This contact is bad because its tel property has a tel.type null
160 // value (upgrade 16 to 17), and email.type not array value (upgrade 14
161 // to 15)
162 "properties": {
163 "name": ["name-bad-4"],
164 "email": [{
165 "value": "toto@toto.com",
166 "type": "home"
167 }],
168 "url": [{
169 "type": ["source"],
170 "value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654"
171 }],
172 "category": ["gmail"],
173 "adr": [],
174 "tel": [{
175 "type": null,
176 "value": "+7 123 456-78-90"
177 }],
178 "sex": "undefined",
179 "genderIdentity": "undefined"
180 },
181 "search": {
182 "givenName": [],
183 "familyName": [],
184 "email": [],
185 "category": ["gmail"],
186 "tel": ["+71234567890","71234567890","1234567890","234567890","34567890",
187 "4567890","567890","67890","7890","890","90","0","81234567890"],
188 "exactTel": ["+71234567890"],
189 "parsedTel": ["+71234567890","1234567890","81234567890","34567890"]
190 },
191 "updated": new Date("2013-07-27T16:47:40.974Z"),
192 "published": new Date("2013-07-27T16:47:40.974Z"),
193 "id": "bad-4"
194 }
195 ],
196 GOOD: [
197 {
198 "properties": {
199 "name": ["name-good-1"],
200 "email": [],
201 "url": [{
202 "type": ["source"],
203 "value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654"
204 }],
205 "category": ["gmail"],
206 "adr": [],
207 "tel": [{
208 "type": ["mobile"],
209 "value": "+7 123 456-78-90"
210 }],
211 "sex": "undefined",
212 "genderIdentity": "undefined"
213 },
214 "search": {
215 "givenName": [],
216 "familyName": [],
217 "email": [],
218 "category": ["gmail"],
219 "tel": ["+71234567890","71234567890","1234567890","234567890","34567890",
220 "4567890","567890","67890","7890","890","90","0","81234567890"],
221 "exactTel": ["+71234567890"],
222 "parsedTel": ["+71234567890","1234567890","81234567890","34567890"]
223 },
224 "updated": new Date("2013-07-27T16:47:40.974Z"),
225 "published": new Date("2013-07-27T16:47:40.974Z"),
226 "id": "good-1"
227 }
228 ]
229 }
230 };
232 function DataManager(version) {
233 if (!(version in DATA)) {
234 throw new Error("Version " + version + " can't be found in our test datas.");
235 }
237 this.version = version;
238 this.data = DATA[version];
239 }
241 DataManager.prototype = {
242 open: function() {
243 debug("opening for version " + this.version);
244 var deferred = Promise.defer();
246 let req = indexedDB.open(DB_NAME, this.version);
247 req.onupgradeneeded = function() {
248 let db = req.result;
249 let transaction = req.transaction;
250 this.createSchema(db, transaction);
251 this.addContacts(db, transaction);
252 }.bind(this);
254 req.onsuccess = function() {
255 debug("succeeded opening the db, let's close it now");
256 req.result.close();
257 deferred.resolve(this.contactsCount());
258 }.bind(this);
260 req.onerror = function() {
261 deferred.reject(this.error);
262 };
264 return deferred.promise;
265 },
267 createSchema: function(db, transaction) {
268 debug("createSchema for version " + this.version);
269 this.data.SCHEMA(db, transaction);
270 },
272 addContacts: function(db, transaction) {
273 debug("adding contacts for version " + this.version);
274 var os = transaction.objectStore(STORE_NAME);
276 this.data.GOOD.forEach(function(contact) {
277 os.put(contact);
278 });
279 this.data.BAD.forEach(function(contact) {
280 os.put(contact);
281 });
282 },
284 contactsCount: function() {
285 return this.data.BAD.length + this.data.GOOD.length;
286 }
287 };
289 DataManager.delete = function() {
290 debug("Deleting the database");
291 var deferred = Promise.defer();
293 /* forcibly close the db before deleting it */
294 ContactService._db.close();
296 var req = indexedDB.deleteDatabase(DB_NAME);
297 req.onsuccess = function() {
298 debug("Successfully deleted!");
299 deferred.resolve();
300 };
302 req.onerror = function() {
303 debug("Not deleted, error is " + this.error.name);
304 deferred.reject(this.error);
305 };
307 req.onblocked = function() {
308 debug("Waiting for the current users");
309 };
311 return deferred.promise;
312 };
314 addMessageListener("createDB", function(version) {
315 // Promises help handling gracefully exceptions
316 Promise.resolve().then(function() {
317 return new DataManager(version);
318 }).then(function(manager) {
319 return manager.open();
320 }).then(function onSuccess(count) {
321 sendAsyncMessage("createDB.success", count);
322 }, function onError(err) {
323 sendAsyncMessage("createDB.error", "Failed to create the DB: " +
324 "(" + err.name + ") " + err.message);
325 });
326 });
328 addMessageListener("deleteDB", function() {
329 Promise.resolve().then(
330 DataManager.delete
331 ).then(function onSuccess() {
332 sendAsyncMessage("deleteDB.success");
333 }, function onError(err) {
334 sendAsyncMessage("deleteDB.error", "Failed to delete the DB:" + err.name);
335 });
336 });