summaryrefslogtreecommitdiffstats
path: root/services/sync/tps/extensions/tps/resource/modules/history.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'services/sync/tps/extensions/tps/resource/modules/history.jsm')
-rw-r--r--services/sync/tps/extensions/tps/resource/modules/history.jsm207
1 files changed, 207 insertions, 0 deletions
diff --git a/services/sync/tps/extensions/tps/resource/modules/history.jsm b/services/sync/tps/extensions/tps/resource/modules/history.jsm
new file mode 100644
index 000000000..78deb42ab
--- /dev/null
+++ b/services/sync/tps/extensions/tps/resource/modules/history.jsm
@@ -0,0 +1,207 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+ /* This is a JavaScript module (JSM) to be imported via
+ * Components.utils.import() and acts as a singleton. Only the following
+ * listed symbols will exposed on import, and only when and where imported.
+ */
+
+var EXPORTED_SYMBOLS = ["HistoryEntry", "DumpHistory"];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/PlacesUtils.jsm");
+Cu.import("resource://tps/logger.jsm");
+Cu.import("resource://services-common/async.js");
+
+var DumpHistory = function TPS_History__DumpHistory() {
+ let writer = {
+ value: "",
+ write: function PlacesItem__dump__write(aStr, aLen) {
+ this.value += aStr;
+ }
+ };
+
+ let query = PlacesUtils.history.getNewQuery();
+ let options = PlacesUtils.history.getNewQueryOptions();
+ let root = PlacesUtils.history.executeQuery(query, options).root;
+ root.containerOpen = true;
+ Logger.logInfo("\n\ndumping history\n", true);
+ for (var i = 0; i < root.childCount; i++) {
+ let node = root.getChild(i);
+ let uri = node.uri;
+ let curvisits = HistoryEntry._getVisits(uri);
+ for (var visit of curvisits) {
+ Logger.logInfo("URI: " + uri + ", type=" + visit.type + ", date=" + visit.date, true);
+ }
+ }
+ root.containerOpen = false;
+ Logger.logInfo("\nend history dump\n", true);
+};
+
+/**
+ * HistoryEntry object
+ *
+ * Contains methods for manipulating browser history entries.
+ */
+var HistoryEntry = {
+ /**
+ * _db
+ *
+ * Returns the DBConnection object for the history service.
+ */
+ get _db() {
+ return PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
+ },
+
+ /**
+ * _visitStm
+ *
+ * Return the SQL statement for getting history visit information
+ * from the moz_historyvisits table. Borrowed from Weave's
+ * history.js.
+ */
+ get _visitStm() {
+ let stm = this._db.createStatement(
+ "SELECT visit_type type, visit_date date " +
+ "FROM moz_historyvisits " +
+ "WHERE place_id = (" +
+ "SELECT id " +
+ "FROM moz_places " +
+ "WHERE url_hash = hash(:url) AND url = :url) " +
+ "ORDER BY date DESC LIMIT 20");
+ this.__defineGetter__("_visitStm", () => stm);
+ return stm;
+ },
+
+ /**
+ * _getVisits
+ *
+ * Gets history information about visits to a given uri.
+ *
+ * @param uri The uri to get visits for
+ * @return an array of objects with 'date' and 'type' properties,
+ * corresponding to the visits in the history database for the
+ * given uri
+ */
+ _getVisits: function HistStore__getVisits(uri) {
+ this._visitStm.params.url = uri;
+ return Async.querySpinningly(this._visitStm, ["date", "type"]);
+ },
+
+ /**
+ * Add
+ *
+ * Adds visits for a uri to the history database. Throws on error.
+ *
+ * @param item An object representing one or more visits to a specific uri
+ * @param usSinceEpoch The number of microseconds from Epoch to
+ * the time the current Crossweave run was started
+ * @return nothing
+ */
+ Add: function(item, usSinceEpoch) {
+ Logger.AssertTrue("visits" in item && "uri" in item,
+ "History entry in test file must have both 'visits' " +
+ "and 'uri' properties");
+ let uri = Services.io.newURI(item.uri, null, null);
+ let place = {
+ uri: uri,
+ visits: []
+ };
+ for (let visit of item.visits) {
+ place.visits.push({
+ visitDate: usSinceEpoch + (visit.date * 60 * 60 * 1000 * 1000),
+ transitionType: visit.type
+ });
+ }
+ if ("title" in item) {
+ place.title = item.title;
+ }
+ let cb = Async.makeSpinningCallback();
+ PlacesUtils.asyncHistory.updatePlaces(place, {
+ handleError: function Add_handleError() {
+ cb(new Error("Error adding history entry"));
+ },
+ handleResult: function Add_handleResult() {
+ cb();
+ },
+ handleCompletion: function Add_handleCompletion() {
+ // Nothing to do
+ }
+ });
+ // Spin the event loop to embed this async call in a sync API
+ cb.wait();
+ },
+
+ /**
+ * Find
+ *
+ * Finds visits for a uri to the history database. Throws on error.
+ *
+ * @param item An object representing one or more visits to a specific uri
+ * @param usSinceEpoch The number of microseconds from Epoch to
+ * the time the current Crossweave run was started
+ * @return true if all the visits for the uri are found, otherwise false
+ */
+ Find: function(item, usSinceEpoch) {
+ Logger.AssertTrue("visits" in item && "uri" in item,
+ "History entry in test file must have both 'visits' " +
+ "and 'uri' properties");
+ let curvisits = this._getVisits(item.uri);
+ for (let visit of curvisits) {
+ for (let itemvisit of item.visits) {
+ let expectedDate = itemvisit.date * 60 * 60 * 1000 * 1000
+ + usSinceEpoch;
+ if (visit.type == itemvisit.type && visit.date == expectedDate) {
+ itemvisit.found = true;
+ }
+ }
+ }
+
+ let all_items_found = true;
+ for (let itemvisit of item.visits) {
+ all_items_found = all_items_found && "found" in itemvisit;
+ Logger.logInfo("History entry for " + item.uri + ", type:" +
+ itemvisit.type + ", date:" + itemvisit.date +
+ ("found" in itemvisit ? " is present" : " is not present"));
+ }
+ return all_items_found;
+ },
+
+ /**
+ * Delete
+ *
+ * Removes visits from the history database. Throws on error.
+ *
+ * @param item An object representing items to delete
+ * @param usSinceEpoch The number of microseconds from Epoch to
+ * the time the current Crossweave run was started
+ * @return nothing
+ */
+ Delete: function(item, usSinceEpoch) {
+ if ("uri" in item) {
+ let uri = Services.io.newURI(item.uri, null, null);
+ PlacesUtils.history.removePage(uri);
+ }
+ else if ("host" in item) {
+ PlacesUtils.history.removePagesFromHost(item.host, false);
+ }
+ else if ("begin" in item && "end" in item) {
+ let cb = Async.makeSpinningCallback();
+ let msSinceEpoch = parseInt(usSinceEpoch / 1000);
+ let filter = {
+ beginDate: new Date(msSinceEpoch + (item.begin * 60 * 60 * 1000)),
+ endDate: new Date(msSinceEpoch + (item.end * 60 * 60 * 1000))
+ };
+ PlacesUtils.history.removeVisitsByFilter(filter)
+ .catch(ex => Logger.AssertTrue(false, "An error occurred while deleting history: " + ex))
+ .then(result => {cb(null, result)}, err => {cb(err)});
+ Async.waitForSyncCallback(cb);
+ }
+ else {
+ Logger.AssertTrue(false, "invalid entry in delete history");
+ }
+ },
+};