зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1686554 - Remove newtab Pocket story min scores. r=gvn
Differential Revision: https://phabricator.services.mozilla.com/D106507
This commit is contained in:
Родитель
ca416daff0
Коммит
3ca2aa9b23
|
@ -978,13 +978,6 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
|
||||||
items.map(item => this.scoreItem(item, personalizedByType))
|
items.map(item => this.scoreItem(item, personalizedByType))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
// Remove spocs that are scored too low.
|
|
||||||
.filter(s => {
|
|
||||||
if (s.score >= s.min_score) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
})
|
|
||||||
// Sort by highest scores.
|
// Sort by highest scores.
|
||||||
.sort(this.sortItem);
|
.sort(this.sortItem);
|
||||||
|
|
||||||
|
@ -993,7 +986,6 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
|
||||||
|
|
||||||
async scoreItem(item, personalizedByType) {
|
async scoreItem(item, personalizedByType) {
|
||||||
item.score = item.item_score;
|
item.score = item.item_score;
|
||||||
item.min_score = item.min_score || 0;
|
|
||||||
if (item.score !== 0 && !item.score) {
|
if (item.score !== 0 && !item.score) {
|
||||||
item.score = 1;
|
item.score = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,9 +210,7 @@ this.TopStoriesFeed = class TopStoriesFeed {
|
||||||
this.spocCampaignMap = new Map(
|
this.spocCampaignMap = new Map(
|
||||||
body.spocs.map(s => [s.id, `${s.campaign_id}`])
|
body.spocs.map(s => [s.id, `${s.campaign_id}`])
|
||||||
);
|
);
|
||||||
this.spocs = this.transform(body.spocs).filter(
|
this.spocs = this.transform(body.spocs);
|
||||||
s => s.score >= s.min_score
|
|
||||||
);
|
|
||||||
this.cleanUpCampaignImpressionPref();
|
this.cleanUpCampaignImpressionPref();
|
||||||
}
|
}
|
||||||
this.storiesLastUpdated = Date.now();
|
this.storiesLastUpdated = Date.now();
|
||||||
|
@ -237,9 +235,7 @@ this.TopStoriesFeed = class TopStoriesFeed {
|
||||||
this.spocCampaignMap = new Map(
|
this.spocCampaignMap = new Map(
|
||||||
data.stories.spocs.map(s => [s.id, `${s.campaign_id}`])
|
data.stories.spocs.map(s => [s.id, `${s.campaign_id}`])
|
||||||
);
|
);
|
||||||
this.spocs = this.transform(data.stories.spocs).filter(
|
this.spocs = this.transform(data.stories.spocs);
|
||||||
s => s.score >= s.min_score
|
|
||||||
);
|
|
||||||
this.cleanUpCampaignImpressionPref();
|
this.cleanUpCampaignImpressionPref();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -273,7 +269,6 @@ this.TopStoriesFeed = class TopStoriesFeed {
|
||||||
image: this.normalizeUrl(s.image_src),
|
image: this.normalizeUrl(s.image_src),
|
||||||
referrer: this.stories_referrer,
|
referrer: this.stories_referrer,
|
||||||
url: s.url,
|
url: s.url,
|
||||||
min_score: s.min_score || 0,
|
|
||||||
score: s.item_score || 1,
|
score: s.item_score || 1,
|
||||||
spoc_meta: this.show_spocs
|
spoc_meta: this.show_spocs
|
||||||
? { campaign_id: s.campaign_id, caps: s.caps }
|
? { campaign_id: s.campaign_id, caps: s.caps }
|
||||||
|
|
|
@ -877,7 +877,7 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
title: "",
|
title: "",
|
||||||
sponsor: "",
|
sponsor: "",
|
||||||
sponsored_by_override: undefined,
|
sponsored_by_override: undefined,
|
||||||
items: [{ id: "data", min_score: 0, score: 1 }],
|
items: [{ id: "data", score: 1 }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
lastUpdated: 0,
|
lastUpdated: 0,
|
||||||
|
@ -885,7 +885,7 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
|
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
feed.store.getState().DiscoveryStream.spocs.data.spocs.items[0],
|
feed.store.getState().DiscoveryStream.spocs.data.spocs.items[0],
|
||||||
{ id: "data", min_score: 0, score: 1 }
|
{ id: "data", score: 1 }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("should normalizeSpocsItems for older spoc data", async () => {
|
it("should normalizeSpocsItems for older spoc data", async () => {
|
||||||
|
@ -899,7 +899,7 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
|
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
feed.store.getState().DiscoveryStream.spocs.data.spocs.items[0],
|
feed.store.getState().DiscoveryStream.spocs.data.spocs.items[0],
|
||||||
{ id: "data", min_score: 0, score: 1 }
|
{ id: "data", score: 1 }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it("should call personalizationVersionOverride with feature_flags", async () => {
|
it("should call personalizationVersionOverride with feature_flags", async () => {
|
||||||
|
@ -937,7 +937,7 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
context: "",
|
context: "",
|
||||||
sponsor: "",
|
sponsor: "",
|
||||||
sponsored_by_override: undefined,
|
sponsored_by_override: undefined,
|
||||||
items: [{ id: "data", score: 1, min_score: 0 }],
|
items: [{ id: "data", score: 1 }],
|
||||||
},
|
},
|
||||||
placement2: {
|
placement2: {
|
||||||
title: "",
|
title: "",
|
||||||
|
@ -972,7 +972,7 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
context: "context",
|
context: "context",
|
||||||
sponsor: "",
|
sponsor: "",
|
||||||
sponsored_by_override: undefined,
|
sponsored_by_override: undefined,
|
||||||
items: [{ id: "data", score: 1, min_score: 0 }],
|
items: [{ id: "data", score: 1 }],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1173,26 +1173,28 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
|
|
||||||
it("should sort based on item_score", async () => {
|
it("should sort based on item_score", async () => {
|
||||||
const { data: result } = await feed.scoreItems([
|
const { data: result } = await feed.scoreItems([
|
||||||
{ id: 2, flight_id: 2, item_score: 0.8, min_score: 0.1 },
|
{ id: 2, flight_id: 2, item_score: 0.8 },
|
||||||
{ id: 3, flight_id: 3, item_score: 0.7, min_score: 0.1 },
|
{ id: 4, flight_id: 4, item_score: 0.5 },
|
||||||
{ id: 1, flight_id: 1, item_score: 0.9, min_score: 0.1 },
|
{ id: 3, flight_id: 3, item_score: 0.7 },
|
||||||
|
{ id: 1, flight_id: 1, item_score: 0.9 },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert.deepEqual(result, [
|
assert.deepEqual(result, [
|
||||||
{ id: 1, flight_id: 1, item_score: 0.9, score: 0.9, min_score: 0.1 },
|
{ id: 1, flight_id: 1, item_score: 0.9, score: 0.9 },
|
||||||
{ id: 2, flight_id: 2, item_score: 0.8, score: 0.8, min_score: 0.1 },
|
{ id: 2, flight_id: 2, item_score: 0.8, score: 0.8 },
|
||||||
{ id: 3, flight_id: 3, item_score: 0.7, score: 0.7, min_score: 0.1 },
|
{ id: 3, flight_id: 3, item_score: 0.7, score: 0.7 },
|
||||||
|
{ id: 4, flight_id: 4, item_score: 0.5, score: 0.5 },
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should sort based on priority", async () => {
|
it("should sort based on priority", async () => {
|
||||||
const { data: result } = await feed.scoreItems([
|
const { data: result } = await feed.scoreItems([
|
||||||
{ id: 6, flight_id: 6, priority: 2, item_score: 0.7, min_score: 0.1 },
|
{ id: 6, flight_id: 6, priority: 2, item_score: 0.7 },
|
||||||
{ id: 2, flight_id: 3, priority: 1, item_score: 0.2, min_score: 0.1 },
|
{ id: 2, flight_id: 3, priority: 1, item_score: 0.2 },
|
||||||
{ id: 4, flight_id: 4, item_score: 0.6, min_score: 0.1 },
|
{ id: 4, flight_id: 4, item_score: 0.6 },
|
||||||
{ id: 5, flight_id: 5, priority: 2, item_score: 0.8, min_score: 0.1 },
|
{ id: 5, flight_id: 5, priority: 2, item_score: 0.8 },
|
||||||
{ id: 3, flight_id: 3, item_score: 0.8, min_score: 0.1 },
|
{ id: 3, flight_id: 3, item_score: 0.8 },
|
||||||
{ id: 1, flight_id: 1, priority: 1, item_score: 0.3, min_score: 0.1 },
|
{ id: 1, flight_id: 1, priority: 1, item_score: 0.3 },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert.deepEqual(result, [
|
assert.deepEqual(result, [
|
||||||
|
@ -1202,7 +1204,6 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
priority: 1,
|
priority: 1,
|
||||||
score: 0.3,
|
score: 0.3,
|
||||||
item_score: 0.3,
|
item_score: 0.3,
|
||||||
min_score: 0.1,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
|
@ -1210,7 +1211,6 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
priority: 1,
|
priority: 1,
|
||||||
score: 0.2,
|
score: 0.2,
|
||||||
item_score: 0.2,
|
item_score: 0.2,
|
||||||
min_score: 0.1,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 5,
|
id: 5,
|
||||||
|
@ -1218,7 +1218,6 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
priority: 2,
|
priority: 2,
|
||||||
score: 0.8,
|
score: 0.8,
|
||||||
item_score: 0.8,
|
item_score: 0.8,
|
||||||
min_score: 0.1,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 6,
|
id: 6,
|
||||||
|
@ -1226,46 +1225,19 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
priority: 2,
|
priority: 2,
|
||||||
score: 0.7,
|
score: 0.7,
|
||||||
item_score: 0.7,
|
item_score: 0.7,
|
||||||
min_score: 0.1,
|
|
||||||
},
|
},
|
||||||
{ id: 3, flight_id: 3, item_score: 0.8, score: 0.8, min_score: 0.1 },
|
{ id: 3, flight_id: 3, item_score: 0.8, score: 0.8 },
|
||||||
{ id: 4, flight_id: 4, item_score: 0.6, score: 0.6, min_score: 0.1 },
|
{ id: 4, flight_id: 4, item_score: 0.6, score: 0.6 },
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should remove items with scores lower than min_score", async () => {
|
|
||||||
const { data: result } = await feed.scoreItems([
|
|
||||||
{ id: 2, flight_id: 2, item_score: 0.8, min_score: 0.9 },
|
|
||||||
{ id: 3, flight_id: 3, item_score: 0.7, min_score: 0.7 },
|
|
||||||
{ id: 1, flight_id: 1, item_score: 0.9, min_score: 0.8 },
|
|
||||||
]);
|
|
||||||
|
|
||||||
assert.deepEqual(result, [
|
|
||||||
{ id: 1, flight_id: 1, item_score: 0.9, score: 0.9, min_score: 0.8 },
|
|
||||||
{ id: 3, flight_id: 3, item_score: 0.7, score: 0.7, min_score: 0.7 },
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should add a score prop to spocs", async () => {
|
it("should add a score prop to spocs", async () => {
|
||||||
const { data: result } = await feed.scoreItems([
|
const { data: result } = await feed.scoreItems([
|
||||||
{ flight_id: 1, item_score: 0.9, min_score: 0.1 },
|
{ flight_id: 1, item_score: 0.9 },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert.equal(result[0].score, 0.9);
|
assert.equal(result[0].score, 0.9);
|
||||||
});
|
});
|
||||||
it("should score items using item_score and min_score", async () => {
|
|
||||||
const { data: result } = await feed.scoreItems([
|
|
||||||
{ item_score: 0.8, min_score: 0.1 },
|
|
||||||
{ item_score: 0.5, min_score: 0.6 },
|
|
||||||
{ item_score: 0.7, min_score: 0.1 },
|
|
||||||
{ item_score: 0.9, min_score: 0.1 },
|
|
||||||
]);
|
|
||||||
assert.deepEqual(result, [
|
|
||||||
{ item_score: 0.9, score: 0.9, min_score: 0.1 },
|
|
||||||
{ item_score: 0.8, score: 0.8, min_score: 0.1 },
|
|
||||||
{ item_score: 0.7, score: 0.7, min_score: 0.1 },
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("#filterBlocked", () => {
|
describe("#filterBlocked", () => {
|
||||||
|
@ -2547,12 +2519,10 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
recommendations: [
|
recommendations: [
|
||||||
{
|
{
|
||||||
id: "first",
|
id: "first",
|
||||||
min_score: 0.5,
|
|
||||||
item_score: 0.7,
|
item_score: 0.7,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "second",
|
id: "second",
|
||||||
min_score: 0.5,
|
|
||||||
item_score: 0.6,
|
item_score: 0.6,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -2566,17 +2536,14 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
recommendations: [
|
recommendations: [
|
||||||
{
|
{
|
||||||
id: "third",
|
id: "third",
|
||||||
min_score: 0.5,
|
|
||||||
item_score: 0.4,
|
item_score: 0.4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "fourth",
|
id: "fourth",
|
||||||
min_score: 0.5,
|
|
||||||
item_score: 0.6,
|
item_score: 0.6,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "fifth",
|
id: "fifth",
|
||||||
min_score: 0.5,
|
|
||||||
item_score: 0.8,
|
item_score: 0.8,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -2593,13 +2560,11 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
recommendations: [
|
recommendations: [
|
||||||
{
|
{
|
||||||
id: "second",
|
id: "second",
|
||||||
min_score: 0.5,
|
|
||||||
item_score: 0.6,
|
item_score: 0.6,
|
||||||
score: 0.6,
|
score: 0.6,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "first",
|
id: "first",
|
||||||
min_score: 0.5,
|
|
||||||
item_score: 0.7,
|
item_score: 0.7,
|
||||||
score: 0.7,
|
score: 0.7,
|
||||||
},
|
},
|
||||||
|
@ -2614,16 +2579,19 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
recommendations: [
|
recommendations: [
|
||||||
{
|
{
|
||||||
id: "fifth",
|
id: "fifth",
|
||||||
min_score: 0.5,
|
|
||||||
item_score: 0.8,
|
item_score: 0.8,
|
||||||
score: 0.8,
|
score: 0.8,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "fourth",
|
id: "fourth",
|
||||||
min_score: 0.5,
|
|
||||||
item_score: 0.6,
|
item_score: 0.6,
|
||||||
score: 0.6,
|
score: 0.6,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "third",
|
||||||
|
item_score: 0.4,
|
||||||
|
score: 0.4,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
settings: {
|
settings: {
|
||||||
recsExpireTime,
|
recsExpireTime,
|
||||||
|
@ -2682,15 +2650,12 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
placement1: {
|
placement1: {
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
min_score: 0.5,
|
|
||||||
item_score: 0.6,
|
item_score: 0.6,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
min_score: 0.5,
|
|
||||||
item_score: 0.4,
|
item_score: 0.4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
min_score: 0.5,
|
|
||||||
item_score: 0.8,
|
item_score: 0.8,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -2698,11 +2663,9 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
placement2: {
|
placement2: {
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
min_score: 0.5,
|
|
||||||
item_score: 0.6,
|
item_score: 0.6,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
min_score: 0.5,
|
|
||||||
item_score: 0.8,
|
item_score: 0.8,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -2719,26 +2682,26 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
placement1: {
|
placement1: {
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
min_score: 0.5,
|
|
||||||
score: 0.8,
|
score: 0.8,
|
||||||
item_score: 0.8,
|
item_score: 0.8,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
min_score: 0.5,
|
|
||||||
score: 0.6,
|
score: 0.6,
|
||||||
item_score: 0.6,
|
item_score: 0.6,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
score: 0.4,
|
||||||
|
item_score: 0.4,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
placement2: {
|
placement2: {
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
min_score: 0.5,
|
|
||||||
score: 0.8,
|
score: 0.8,
|
||||||
item_score: 0.8,
|
item_score: 0.8,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
min_score: 0.5,
|
|
||||||
score: 0.6,
|
score: 0.6,
|
||||||
item_score: 0.6,
|
item_score: 0.6,
|
||||||
},
|
},
|
||||||
|
@ -2860,21 +2823,6 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
assert.isTrue(!feed.affinityProvider);
|
assert.isTrue(!feed.affinityProvider);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe("#scoreItems", () => {
|
|
||||||
it("should score items using item_score and min_score", async () => {
|
|
||||||
const { data: result } = await feed.scoreItems([
|
|
||||||
{ item_score: 0.8, min_score: 0.1 },
|
|
||||||
{ item_score: 0.5, min_score: 0.6 },
|
|
||||||
{ item_score: 0.7, min_score: 0.1 },
|
|
||||||
{ item_score: 0.9, min_score: 0.1 },
|
|
||||||
]);
|
|
||||||
assert.deepEqual(result, [
|
|
||||||
{ item_score: 0.9, score: 0.9, min_score: 0.1 },
|
|
||||||
{ item_score: 0.8, score: 0.8, min_score: 0.1 },
|
|
||||||
{ item_score: 0.7, score: 0.7, min_score: 0.1 },
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe("#scoreItem", () => {
|
describe("#scoreItem", () => {
|
||||||
it("should call calculateItemRelevanceScore with affinity provider", async () => {
|
it("should call calculateItemRelevanceScore with affinity provider", async () => {
|
||||||
const item = {};
|
const item = {};
|
||||||
|
@ -2900,16 +2848,5 @@ describe("DiscoveryStreamFeed", () => {
|
||||||
const result = await feed.scoreItem(item);
|
const result = await feed.scoreItem(item);
|
||||||
assert.equal(result.score, 0.6);
|
assert.equal(result.score, 0.6);
|
||||||
});
|
});
|
||||||
it("should add min_score of 0 if undefined", async () => {
|
|
||||||
const item = {};
|
|
||||||
feed._prefCache.config = {
|
|
||||||
personalized: true,
|
|
||||||
};
|
|
||||||
feed.affinityProvider = {
|
|
||||||
calculateItemRelevanceScore: () => 0.5,
|
|
||||||
};
|
|
||||||
const result = await feed.scoreItem(item);
|
|
||||||
assert.equal(result.min_score, 0);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -500,7 +500,6 @@ describe("Top Stories Feed", () => {
|
||||||
referrer: "referrer",
|
referrer: "referrer",
|
||||||
url: "rec-url",
|
url: "rec-url",
|
||||||
hostname: "rec-url",
|
hostname: "rec-url",
|
||||||
min_score: 0,
|
|
||||||
score: 1,
|
score: 1,
|
||||||
spoc_meta: {},
|
spoc_meta: {},
|
||||||
},
|
},
|
||||||
|
@ -570,7 +569,6 @@ describe("Top Stories Feed", () => {
|
||||||
referrer: "referrer",
|
referrer: "referrer",
|
||||||
url: "rec-url",
|
url: "rec-url",
|
||||||
hostname: "domain",
|
hostname: "domain",
|
||||||
min_score: 0,
|
|
||||||
score: 1,
|
score: 1,
|
||||||
spoc_meta: {},
|
spoc_meta: {},
|
||||||
},
|
},
|
||||||
|
@ -1734,7 +1732,6 @@ describe("Top Stories Feed", () => {
|
||||||
referrer: "referrer",
|
referrer: "referrer",
|
||||||
url: "rec-url",
|
url: "rec-url",
|
||||||
hostname: "rec-url",
|
hostname: "rec-url",
|
||||||
min_score: 0,
|
|
||||||
score: 0.98,
|
score: 0.98,
|
||||||
spoc_meta: {},
|
spoc_meta: {},
|
||||||
},
|
},
|
||||||
|
@ -1806,7 +1803,6 @@ describe("Top Stories Feed", () => {
|
||||||
hostname: undefined,
|
hostname: undefined,
|
||||||
icon: undefined,
|
icon: undefined,
|
||||||
image: undefined,
|
image: undefined,
|
||||||
min_score: 0,
|
|
||||||
referrer: "referrer",
|
referrer: "referrer",
|
||||||
score: 1,
|
score: 1,
|
||||||
spoc_meta: {},
|
spoc_meta: {},
|
||||||
|
|
Загрузка…
Ссылка в новой задаче