For #26706 - Add sponsored urls filter in BlocklistHandler

This commit is contained in:
Alexandru2909 2022-08-30 16:54:04 +03:00 committed by mergify[bot]
parent 070bf5ac24
commit cedb777655
5 changed files with 124 additions and 12 deletions

View File

@ -170,9 +170,9 @@ fun AppState.filterState(blocklistHandler: BlocklistHandler): AppState =
with(blocklistHandler) {
copy(
recentBookmarks = recentBookmarks.filteredByBlocklist(),
recentTabs = recentTabs.filteredByBlocklist(),
recentHistory = recentHistory.filteredByBlocklist(),
recentSyncedTabState = recentSyncedTabState.filteredByBlocklist()
recentTabs = recentTabs.filteredByBlocklist().filterContile(),
recentHistory = recentHistory.filteredByBlocklist().filterContile(),
recentSyncedTabState = recentSyncedTabState.filteredByBlocklist().filterContile()
)
}

View File

@ -4,8 +4,10 @@
package org.mozilla.fenix.home.blocklist
import android.net.Uri
import androidx.annotation.VisibleForTesting
import mozilla.components.support.ktx.kotlin.sha1
import org.mozilla.fenix.ext.containsQueryParameters
import org.mozilla.fenix.home.recentbookmarks.RecentBookmark
import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTabState
import org.mozilla.fenix.home.recenttabs.RecentTab
@ -16,6 +18,8 @@ import org.mozilla.fenix.utils.Settings
* Class for interacting with the a blocklist stored in [settings].
* The blocklist is a set of SHA1 hashed URLs, which are stripped
* of protocols and common subdomains like "www" or "mobile".
*
* Also used for filtering the sponsored URLs.
*/
class BlocklistHandler(private val settings: Settings) {
@ -52,6 +56,14 @@ class BlocklistHandler(private val settings: Settings) {
}
}
/**
* Filter a list of recent tabs from sponsored urls.
*/
@JvmName("filterContileRecentTab")
fun List<RecentTab>.filterContile(): List<RecentTab> = filterNot {
it is RecentTab.Tab &&
Uri.parse(it.state.content.url).containsQueryParameters(settings.frecencyFilterQuery)
}
/**
* If the state is set to [RecentSyncedTabState.Success], filter the list of recently synced
* tabs by the blocklist. If the filtered list of tabs is empty, change the state to
@ -74,6 +86,24 @@ class BlocklistHandler(private val settings: Settings) {
this
}
/**
* Filter a list of recently synced tabs of sponsored urls if the state is
* [RecentSyncedTabState.Success].
*/
@JvmName("filterContileRecentSyncedTab")
fun RecentSyncedTabState.filterContile() = if (this is RecentSyncedTabState.Success) {
val filteredTabs = this.tabs.filterNot {
Uri.parse(it.url).containsQueryParameters(settings.frecencyFilterQuery)
}
if (filteredTabs.isEmpty()) {
RecentSyncedTabState.None
} else {
RecentSyncedTabState.Success(filteredTabs)
}
} else {
this
}
/**
* Filter a list of recent history items by the blocklist. Requires this class to be contextually
* in a scope.
@ -87,6 +117,15 @@ class BlocklistHandler(private val settings: Settings) {
}
}
/**
* Filter a list of recently visited history items of sponsored urls.
*/
@JvmName("filterContileRecentlyVisited")
fun List<RecentlyVisitedItem>.filterContile(): List<RecentlyVisitedItem> = filterNot {
it is RecentlyVisitedItem.RecentHistoryHighlight &&
Uri.parse(it.url).containsQueryParameters(settings.frecencyFilterQuery)
}
private fun blocklistContainsUrl(blocklist: Set<String>, url: String): Boolean =
blocklist.any { it == url.stripAndHash() }
}

View File

@ -41,14 +41,14 @@ class BlocklistMiddleware(
is AppAction.Change -> {
action.copy(
recentBookmarks = action.recentBookmarks.filteredByBlocklist(),
recentTabs = action.recentTabs.filteredByBlocklist(),
recentHistory = action.recentHistory.filteredByBlocklist(),
recentSyncedTabState = action.recentSyncedTabState.filteredByBlocklist()
recentTabs = action.recentTabs.filteredByBlocklist().filterContile(),
recentHistory = action.recentHistory.filteredByBlocklist().filterContile(),
recentSyncedTabState = action.recentSyncedTabState.filteredByBlocklist().filterContile()
)
}
is AppAction.RecentTabsChange -> {
action.copy(
recentTabs = action.recentTabs.filteredByBlocklist()
recentTabs = action.recentTabs.filteredByBlocklist().filterContile()
)
}
is AppAction.RecentBookmarksChange -> {
@ -57,11 +57,11 @@ class BlocklistMiddleware(
)
}
is AppAction.RecentHistoryChange -> {
action.copy(recentHistory = action.recentHistory.filteredByBlocklist())
action.copy(recentHistory = action.recentHistory.filteredByBlocklist().filterContile())
}
is AppAction.RecentSyncedTabStateChange -> {
action.copy(
state = action.state.filteredByBlocklist()
state = action.state.filteredByBlocklist().filterContile()
)
}
is AppAction.RemoveRecentTab -> {
@ -97,14 +97,14 @@ class BlocklistMiddleware(
private fun AppState.toActionFilteringAllState(blocklistHandler: BlocklistHandler) =
with(blocklistHandler) {
AppAction.Change(
recentTabs = recentTabs.filteredByBlocklist(),
recentTabs = recentTabs.filteredByBlocklist().filterContile(),
recentBookmarks = recentBookmarks.filteredByBlocklist(),
recentHistory = recentHistory.filteredByBlocklist(),
recentHistory = recentHistory.filteredByBlocklist().filterContile(),
topSites = topSites,
mode = mode,
collections = collections,
showCollectionPlaceholder = showCollectionPlaceholder,
recentSyncedTabState = recentSyncedTabState.filteredByBlocklist()
recentSyncedTabState = recentSyncedTabState.filteredByBlocklist().filterContile()
)
}
}

View File

@ -5,14 +5,20 @@ import io.mockk.mockk
import io.mockk.slot
import mozilla.components.browser.state.state.ContentState
import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.concept.sync.DeviceType
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.home.recentbookmarks.RecentBookmark
import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTab
import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTabState
import org.mozilla.fenix.home.recenttabs.RecentTab
import org.mozilla.fenix.home.recentvisits.RecentlyVisitedItem
import org.mozilla.fenix.utils.Settings
@RunWith(FenixRobolectricTestRunner::class)
class BlocklistHandlerTest {
private val mockSettings: Settings = mockk()
@ -117,4 +123,65 @@ class BlocklistHandlerTest {
assertEquals(listOf<String>(), filtered)
}
@Test
fun `GIVEN recently synced tab is a sponsored url WHEN the tabs are filtered THEN the sponsored url be filtered`() {
val blockedUrl = "test.com/?query=value"
val mockSessionState: TabSessionState = mockk()
val mockContent: ContentState = mockk()
val tabs = RecentSyncedTabState.Success(
listOf(
RecentSyncedTab(
"",
DeviceType.DESKTOP,
"title",
blockedUrl,
null
)
)
)
every { mockSessionState.content } returns mockContent
every { mockContent.url } returns blockedUrl
every { mockSettings.frecencyFilterQuery } returns "query=value"
val filtered = with(blocklistHandler) {
tabs.filterContile()
}
assertEquals(RecentSyncedTabState.None, filtered)
}
@Test
fun `GIVEN recently visited item is a sponsored url WHEN the tabs are filtered THEN the sponsored url be filtered`() {
val blockedUrl = "test.com/?query=value"
val mockSessionState: TabSessionState = mockk()
val mockContent: ContentState = mockk()
val tabs = listOf(RecentlyVisitedItem.RecentHistoryHighlight("title", blockedUrl))
every { mockSessionState.content } returns mockContent
every { mockContent.url } returns blockedUrl
every { mockSettings.frecencyFilterQuery } returns "query=value"
val filtered = with(blocklistHandler) {
tabs.filterContile()
}
assertEquals(listOf<String>(), filtered)
}
@Test
fun `GIVEN recent tab is a sponsored url WHEN the tabs are filtered THEN the sponsored url be filtered`() {
val blockedUrl = "test.com/?query=value"
val mockSessionState: TabSessionState = mockk()
val mockContent: ContentState = mockk()
val tabs = listOf(RecentTab.Tab(mockSessionState))
every { mockSessionState.content } returns mockContent
every { mockContent.url } returns blockedUrl
every { mockSettings.frecencyFilterQuery } returns "query=value"
val filtered = with(blocklistHandler) {
tabs.filterContile()
}
assertEquals(listOf<String>(), filtered)
}
}

View File

@ -14,15 +14,18 @@ import mozilla.components.support.test.mock
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.components.AppStore
import org.mozilla.fenix.components.appstate.AppAction
import org.mozilla.fenix.components.appstate.AppState
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.home.recentbookmarks.RecentBookmark
import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTab
import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTabState
import org.mozilla.fenix.home.recenttabs.RecentTab
import org.mozilla.fenix.utils.Settings
@RunWith(FenixRobolectricTestRunner::class)
class BlocklistMiddlewareTest {
private val mockSettings: Settings = mockk()
private val blocklistHandler = BlocklistHandler(mockSettings)
@ -178,6 +181,7 @@ class BlocklistMiddlewareTest {
listOf(RecentTab.Tab(createTab(url = blockedUrl)), unblockedRecentTab)
every { mockSettings.homescreenBlocklist } returns setOf(blockedUrl.stripAndHash())
every { mockSettings.frecencyFilterQuery } returns ""
val middleware = BlocklistMiddleware(blocklistHandler)
val store = AppStore(
AppState(),
@ -328,6 +332,7 @@ class BlocklistMiddlewareTest {
)
every { mockSettings.homescreenBlocklist } returns setOf(blockedHost.stripAndHash())
every { mockSettings.frecencyFilterQuery } returns ""
val middleware = BlocklistMiddleware(blocklistHandler)
val store = AppStore(
AppState(),
@ -435,6 +440,7 @@ class BlocklistMiddlewareTest {
val updateSlot = slot<Set<String>>()
every { mockSettings.homescreenBlocklist = capture(updateSlot) } returns Unit
every { mockSettings.homescreenBlocklist } returns setOf(tabUrls[0].stripAndHash())
every { mockSettings.frecencyFilterQuery } returns ""
store.dispatch(
AppAction.RemoveRecentSyncedTab(