summaryrefslogtreecommitdiffstats
path: root/services/sync/tps/extensions/tps/resource/modules/history.sys.mjs
blob: 845bab3aa910883116f59b0a0c4397783e15304b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* 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
 * ChromeUtils.import() and acts as a singleton. Only the following
 * listed symbols will exposed on import, and only when and where imported.
 */

import { PlacesUtils } from "resource://gre/modules/PlacesUtils.sys.mjs";

import { PlacesSyncUtils } from "resource://gre/modules/PlacesSyncUtils.sys.mjs";

import { Logger } from "resource://tps/logger.sys.mjs";

export var DumpHistory = async function TPS_History__DumpHistory() {
  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 guid = await PlacesSyncUtils.history
      .fetchGuidForURL(uri)
      .catch(() => "?".repeat(12));
    let curvisits = await PlacesSyncUtils.history.fetchVisitsForURL(uri);
    for (var visit of curvisits) {
      Logger.logInfo(
        `GUID: ${guid}, 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.
 */
export var HistoryEntry = {
  /**
   * 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
   */
  async Add(item, msSinceEpoch) {
    Logger.AssertTrue(
      "visits" in item && "uri" in item,
      "History entry in test file must have both 'visits' " +
        "and 'uri' properties"
    );
    let place = {
      url: item.uri,
      visits: [],
    };
    for (let visit of item.visits) {
      let date = new Date(
        Math.round(msSinceEpoch + visit.date * 60 * 60 * 1000)
      );
      place.visits.push({ date, transition: visit.type });
    }
    if ("title" in item) {
      place.title = item.title;
    }
    return PlacesUtils.history.insert(place);
  },

  /**
   * 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
   */
  async Find(item, msSinceEpoch) {
    Logger.AssertTrue(
      "visits" in item && "uri" in item,
      "History entry in test file must have both 'visits' " +
        "and 'uri' properties"
    );
    let curvisits = await PlacesSyncUtils.history.fetchVisitsForURL(item.uri);
    for (let visit of curvisits) {
      for (let itemvisit of item.visits) {
        // Note: in microseconds.
        let expectedDate =
          itemvisit.date * 60 * 60 * 1000 * 1000 + msSinceEpoch * 1000;
        if (visit.type == itemvisit.type) {
          if (itemvisit.date === undefined || 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}` +
          `(${
            itemvisit.date * 60 * 60 * 1000 * 1000
          }), found = ${!!itemvisit.found}`
      );
    }
    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
   */
  async Delete(item, msSinceEpoch) {
    if ("uri" in item) {
      let removedAny = await PlacesUtils.history.remove(item.uri);
      if (!removedAny) {
        Logger.log("Warning: Removed 0 history visits for uri " + item.uri);
      }
    } else if ("host" in item) {
      await PlacesUtils.history.removeByFilter({ host: item.host });
    } else if ("begin" in item && "end" in item) {
      let filter = {
        beginDate: new Date(msSinceEpoch + item.begin * 60 * 60 * 1000),
        endDate: new Date(msSinceEpoch + item.end * 60 * 60 * 1000),
      };
      let removedAny = await PlacesUtils.history.removeVisitsByFilter(filter);
      if (!removedAny) {
        Logger.log(
          "Warning: Removed 0 history visits with " +
            JSON.stringify({ item, filter })
        );
      }
    } else {
      Logger.AssertTrue(
        false,
        "invalid entry in delete history " + JSON.stringify(item)
      );
    }
  },
};