Bug 1425496 - Add Recently Pocketed Items to Highlights r=Mardak
MozReview-Commit-ID: LyXKkQkPXte
This commit is contained in:
@@ -523,7 +523,8 @@ const PanelUI = {
|
||||
// As per bug 1402023, hard-coded limit, until Activity Stream develops a
|
||||
// richer list.
|
||||
numItems: 6,
|
||||
withFavicons: true
|
||||
withFavicons: true,
|
||||
excludePocket: true
|
||||
}).catch(ex => {
|
||||
// Just hide the section if we can't retrieve the items from the database.
|
||||
Cu.reportError(ex);
|
||||
|
||||
@@ -87,7 +87,8 @@ this.HighlightsFeed = class HighlightsFeed {
|
||||
|
||||
// Request more than the expected length to allow for items being removed by
|
||||
// deduping against Top Sites or multiple history from the same domain, etc.
|
||||
const manyPages = await this.linksCache.request({numItems: MANY_EXTRA_LENGTH});
|
||||
// Until bug 1425496 lands, do not include saved Pocket items in highlights
|
||||
const manyPages = await this.linksCache.request({numItems: MANY_EXTRA_LENGTH, excludePocket: true});
|
||||
|
||||
// Remove adult highlights if we need to
|
||||
const checkedAdult = this.store.getState().Prefs.values.filterAdult ?
|
||||
|
||||
@@ -23,6 +23,9 @@ ChromeUtils.defineModuleGetter(this, "PageThumbs",
|
||||
ChromeUtils.defineModuleGetter(this, "BinarySearch",
|
||||
"resource://gre/modules/BinarySearch.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "pktApi",
|
||||
"chrome://pocket/content/pktApi.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gCryptoHash", function() {
|
||||
return Cc["@mozilla.org/security/hash;1"].createInstance(Ci.nsICryptoHash);
|
||||
});
|
||||
@@ -955,6 +958,11 @@ var ActivityStreamProvider = {
|
||||
// the original link object. We must wait until all favicons for the array
|
||||
// of links are computed before returning
|
||||
return Promise.all(aLinks.map(link => new Promise(async resolve => {
|
||||
// Never add favicon data for pocket items
|
||||
if (link.type === "pocket") {
|
||||
resolve(link);
|
||||
return;
|
||||
}
|
||||
let iconData;
|
||||
try {
|
||||
const linkUri = Services.io.newURI(link.url);
|
||||
@@ -974,6 +982,67 @@ var ActivityStreamProvider = {
|
||||
})));
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper function which makes the call to the Pocket API to fetch the user's
|
||||
* saved Pocket items.
|
||||
*/
|
||||
fetchSavedPocketItems(requestData) {
|
||||
if (!pktApi.isUserLoggedIn()) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
pktApi.retrieve(requestData, {
|
||||
success(data) {
|
||||
resolve(data);
|
||||
},
|
||||
error(error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the most recently Pocket-ed items from a user's Pocket list. See:
|
||||
* https://getpocket.com/developer/docs/v3/retrieve for details
|
||||
*
|
||||
* @param {Object} aOptions
|
||||
* {int} numItems: The max number of pocket items to fetch
|
||||
*/
|
||||
async getRecentlyPocketed(aOptions) {
|
||||
const pocketSecondsAgo = Math.floor(Date.now() / 1000) - ACTIVITY_STREAM_DEFAULT_RECENT;
|
||||
const requestData = {
|
||||
detailType: "complete",
|
||||
count: aOptions.numItems,
|
||||
since: pocketSecondsAgo
|
||||
};
|
||||
let data;
|
||||
try {
|
||||
data = await this.fetchSavedPocketItems(requestData);
|
||||
if (!data) {
|
||||
return [];
|
||||
}
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
return [];
|
||||
}
|
||||
/* Extract relevant parts needed to show this card as a highlight:
|
||||
* url, preview image, title, description, and the unique item_id
|
||||
* necessary for Pocket to identify the item
|
||||
*/
|
||||
let items = Object.values(data.list)
|
||||
// status "0" means not archived or deleted
|
||||
.filter(item => item.status === "0")
|
||||
.map(item => ({
|
||||
description: item.excerpt,
|
||||
preview_image_url: item.has_image === "1" && item.image.src,
|
||||
title: item.resolved_title,
|
||||
url: item.resolved_url,
|
||||
item_id: item.item_id
|
||||
}));
|
||||
return this._processHighlights(items, aOptions, "pocket");
|
||||
},
|
||||
|
||||
/**
|
||||
* Get most-recently-created visited bookmarks for Activity Stream.
|
||||
*
|
||||
@@ -1296,6 +1365,7 @@ var ActivityStreamLinks = {
|
||||
* @param {Object} aOptions
|
||||
* {bool} excludeBookmarks: Don't add bookmark items.
|
||||
* {bool} excludeHistory: Don't add history items.
|
||||
* {bool} excludePocket: Don't add Pocket items.
|
||||
* {bool} withFavicons: Add favicon data: URIs, when possible.
|
||||
* {int} numItems: Maximum number of (bookmark or history) items to return.
|
||||
*
|
||||
@@ -1310,6 +1380,11 @@ var ActivityStreamLinks = {
|
||||
results.push(...await ActivityStreamProvider.getRecentBookmarks(aOptions));
|
||||
}
|
||||
|
||||
// Add the Pocket items if we need more and want them
|
||||
if (aOptions.numItems - results.length > 0 && !aOptions.excludePocket) {
|
||||
results.push(...await ActivityStreamProvider.getRecentlyPocketed(aOptions));
|
||||
}
|
||||
|
||||
// Add in history if we need more and want them
|
||||
if (aOptions.numItems - results.length > 0 && !aOptions.excludeHistory) {
|
||||
// Use the same numItems as bookmarks above in case we remove duplicates
|
||||
|
||||
@@ -376,9 +376,17 @@ add_task(async function addFavicons() {
|
||||
Assert.equal(nonHttps[0].faviconLength, links[0].faviconLength, "Got the same favicon length");
|
||||
Assert.equal(nonHttps[0].faviconSize, links[0].faviconSize, "Got the same favicon size");
|
||||
Assert.equal(nonHttps[0].mimeType, links[0].mimeType, "Got the same mime type");
|
||||
|
||||
// Check that we do not collect favicons for pocket items
|
||||
const pocketItems = [{url: links[0].url}, {url: "https://mozilla1.com", type: "pocket"}];
|
||||
await provider._addFavicons(pocketItems);
|
||||
Assert.equal(provider._faviconBytesToDataURI(pocketItems)[0].favicon, base64URL, "Added favicon data only to the non-pocket item");
|
||||
Assert.equal(pocketItems[1].favicon, null, "Did not add a favicon to the pocket item");
|
||||
Assert.equal(pocketItems[1].mimeType, null, "Did not add mimeType to the pocket item");
|
||||
Assert.equal(pocketItems[1].faviconSize, null, "Did not add a faviconSize to the pocket item");
|
||||
});
|
||||
|
||||
add_task(async function getHighlights() {
|
||||
add_task(async function getHighlightsWithoutPocket() {
|
||||
const addMetadata = url => PlacesUtils.history.update({
|
||||
description: "desc",
|
||||
previewImageURL: "https://image/",
|
||||
@@ -499,6 +507,79 @@ add_task(async function getHighlights() {
|
||||
Assert.equal(links[2].favicon, null, "Link 3 has no favicon data");
|
||||
});
|
||||
|
||||
add_task(async function getHighlightsWithPocketSuccess() {
|
||||
await setUpActivityStreamTest();
|
||||
|
||||
const fakeResponse = {
|
||||
list: {
|
||||
"12345": {
|
||||
image: {src: "foo.com/img.png"},
|
||||
excerpt: "A description for foo",
|
||||
resolved_title: "A title for foo",
|
||||
resolved_url: "http://www.foo.com",
|
||||
item_id: "12345",
|
||||
status: "0",
|
||||
has_image: "1"
|
||||
},
|
||||
"56789": {
|
||||
item_id: "56789",
|
||||
status: "2",
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Add a bookmark
|
||||
let bookmark = {
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
title: "foo",
|
||||
description: "desc",
|
||||
preview_image_url: "foo.com/img.png",
|
||||
url: "https://mozilla1.com/"
|
||||
};
|
||||
await PlacesUtils.bookmarks.insert(bookmark);
|
||||
await PlacesTestUtils.addVisits(bookmark.url);
|
||||
|
||||
NewTabUtils.activityStreamProvider.fetchSavedPocketItems = () => fakeResponse;
|
||||
let provider = NewTabUtils.activityStreamLinks;
|
||||
let links = await provider.getHighlights();
|
||||
|
||||
// We should have 1 bookmark followed by 1 pocket story in highlights
|
||||
// We should not have stored the second pocket item since it was deleted
|
||||
Assert.equal(links.length, 2, "Should have 2 links in highlights");
|
||||
|
||||
// First highlight should be a bookmark
|
||||
Assert.equal(links[0].url, bookmark.url, "The first link is the bookmark");
|
||||
|
||||
// Second highlight should be a Pocket item with the correct fields to display
|
||||
Assert.equal(links[1].url, fakeResponse.list["12345"].resolved_url, "Correct Pocket item");
|
||||
Assert.equal(links[1].type, "pocket", "Attached the correct type");
|
||||
Assert.equal(links[1].preview_image_url, fakeResponse.list["12345"].image.src, "Correct preview image was added");
|
||||
Assert.equal(links[1].title, fakeResponse.list["12345"].resolved_title, "Correct title was added");
|
||||
Assert.equal(links[1].description, fakeResponse.list["12345"].excerpt, "Correct description was added");
|
||||
Assert.equal(links[1].item_id, fakeResponse.list["12345"].item_id, "item_id was preserved");
|
||||
});
|
||||
|
||||
add_task(async function getHighlightsWithPocketFailure() {
|
||||
await setUpActivityStreamTest();
|
||||
|
||||
NewTabUtils.activityStreamProvider.fetchSavedPocketItems = function() {
|
||||
throw new Error();
|
||||
};
|
||||
let provider = NewTabUtils.activityStreamLinks;
|
||||
let links = await provider.getHighlights();
|
||||
Assert.equal(links.length, 0, "Return empty links if we reject the promise");
|
||||
});
|
||||
|
||||
add_task(async function getHighlightsWithPocketNoData() {
|
||||
await setUpActivityStreamTest();
|
||||
|
||||
NewTabUtils.activityStreamProvider.fetchSavedPocketItems = () => {};
|
||||
|
||||
let provider = NewTabUtils.activityStreamLinks;
|
||||
let links = await provider.getHighlights();
|
||||
Assert.equal(links.length, 0, "Return empty links if we got no data back from the response");
|
||||
});
|
||||
|
||||
add_task(async function getTopFrecentSites() {
|
||||
await setUpActivityStreamTest();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user