Merge pull request #3143 from vector-im/feature/bma/discovery_filtering

Filter some other words when navigating into the room directory
This commit is contained in:
Benoit Marty 2021-04-09 08:52:32 +02:00 committed by GitHub
commit 2d6fca9214
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 256 additions and 12 deletions

View File

@ -0,0 +1,128 @@
/*
* Copyright (c) 2021 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.roomdirectory
import im.vector.app.InstrumentedTest
import im.vector.app.core.utils.AssetReader
import org.amshove.kluent.shouldBe
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import org.junit.runners.MethodSorters
@RunWith(JUnit4::class)
@FixMethodOrder(MethodSorters.JVM)
class ExplicitTermFilterTest : InstrumentedTest {
private val explicitTermFilter = ExplicitTermFilter(AssetReader(context()))
@Test
fun isValidEmptyTrue() {
explicitTermFilter.isValid("") shouldBe true
}
@Test
fun isValidTrue() {
explicitTermFilter.isValid("Hello") shouldBe true
}
@Test
fun isValidFalse() {
explicitTermFilter.isValid("nsfw") shouldBe false
}
@Test
fun isValidUpCaseFalse() {
explicitTermFilter.isValid("Nsfw") shouldBe false
}
@Test
fun isValidMultilineTrue() {
explicitTermFilter.isValid("Hello\nWorld") shouldBe true
}
@Test
fun isValidMultilineFalse() {
explicitTermFilter.isValid("Hello\nnsfw") shouldBe false
}
@Test
fun isValidMultilineFalse2() {
explicitTermFilter.isValid("nsfw\nHello") shouldBe false
}
@Test
fun isValidAnalFalse() {
explicitTermFilter.isValid("anal") shouldBe false
}
@Test
fun isValidAnal2False() {
explicitTermFilter.isValid("There is some anal in this room") shouldBe false
}
@Test
fun isValidAnalysisTrue() {
explicitTermFilter.isValid("analysis") shouldBe true
}
@Test
fun isValidAnalysis2True() {
explicitTermFilter.isValid("There is some analysis in the room") shouldBe true
}
@Test
fun isValidSpecialCharFalse() {
explicitTermFilter.isValid("18+") shouldBe false
}
@Test
fun isValidSpecialChar2False() {
explicitTermFilter.isValid("This is a room with 18+ content") shouldBe false
}
@Test
fun isValidOtherSpecialCharFalse() {
explicitTermFilter.isValid("strap-on") shouldBe false
}
@Test
fun isValidOtherSpecialChar2False() {
explicitTermFilter.isValid("This is a room with strap-on content") shouldBe false
}
@Test
fun isValid18True() {
explicitTermFilter.isValid("18") shouldBe true
}
@Test
fun isValidLastFalse() {
explicitTermFilter.isValid("zoo") shouldBe false
}
@Test
fun canSearchForFalse() {
explicitTermFilter.canSearchFor("zoo") shouldBe false
}
@Test
fun canSearchForTrue() {
explicitTermFilter.canSearchFor("android") shouldBe true
}
}

View File

@ -0,0 +1,68 @@
anal
bbw
bdsm
beast
bestiality
blowjob
bondage
boobs
clit
cock
cuck
cum
cunt
daddy
dick
dildo
erotic
exhibitionism
faggot
femboy
fisting
flogging
fmf
foursome
futa
gangbang
gore
h3ntai
handjob
hentai
incest
jizz
kink
loli
m4f
masturbate
masturbation
mfm
milf
moresome
naked
neet
nsfw
nude
nudity
orgy
pedo
pegging
penis
petplay
porn
pussy
rape
rimming
sadism
sadomasochism
sexy
shota
spank
squirt
strap-on
threesome
vagina
vibrator
voyeur
watersports
xxx
zoo

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2021 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.features.roomdirectory
import im.vector.app.core.utils.AssetReader
import javax.inject.Inject
class ExplicitTermFilter @Inject constructor(
assetReader: AssetReader
) {
// List of forbidden terms is in file asset forbidden_terms.txt, in lower case
private val explicitTerms = assetReader.readAssetFile("forbidden_terms.txt")
.orEmpty()
.split("\n")
.map { it.trim() }
.distinct()
.filter { it.isNotEmpty() }
private val explicitContentRegex = explicitTerms
.joinToString(prefix = ".*\\b(", separator = "|", postfix = ")\\b.*")
.toRegex(RegexOption.IGNORE_CASE)
fun canSearchFor(term: String): Boolean {
return term !in explicitTerms && term != "18+"
}
fun isValid(str: String): Boolean {
return explicitContentRegex.matches(str.replace("\n", " ")).not()
// Special treatment for "18+" since word boundaries does not work here
&& str.contains("18+").not()
}
}

View File

@ -42,12 +42,12 @@ import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryDat
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.rx.rx
import timber.log.Timber
import java.util.Locale
class RoomDirectoryViewModel @AssistedInject constructor(
@Assisted initialState: PublicRoomsViewState,
vectorPreferences: VectorPreferences,
private val session: Session
private val session: Session,
private val explicitTermFilter: ExplicitTermFilter
) : VectorViewModel<PublicRoomsViewState, RoomDirectoryAction, RoomDirectoryViewEvents>(initialState) {
@AssistedFactory
@ -58,11 +58,6 @@ class RoomDirectoryViewModel @AssistedInject constructor(
companion object : MvRxViewModelFactory<RoomDirectoryViewModel, PublicRoomsViewState> {
private const val PUBLIC_ROOMS_LIMIT = 20
// List of forbidden terms, in lower case
private val explicitContentTerms = listOf(
"nsfw"
)
@JvmStatic
override fun create(viewModelContext: ViewModelContext, state: PublicRoomsViewState): RoomDirectoryViewModel? {
val activity: RoomDirectoryActivity = (viewModelContext as ActivityViewModelContext).activity()
@ -166,6 +161,17 @@ class RoomDirectoryViewModel @AssistedInject constructor(
}
private fun load(filter: String, roomDirectoryData: RoomDirectoryData) {
if (!showAllRooms && !explicitTermFilter.canSearchFor(filter)) {
setState {
copy(
asyncPublicRoomsRequest = Success(Unit),
publicRooms = emptyList(),
hasMore = false
)
}
return
}
currentJob = viewModelScope.launch {
val data = try {
session.getPublicRooms(roomDirectoryData.homeServer,
@ -202,11 +208,7 @@ class RoomDirectoryViewModel @AssistedInject constructor(
// Filter
val newPublicRooms = data.chunk.orEmpty()
.filter {
showAllRooms
|| "${it.name.orEmpty()} ${it.topic.orEmpty()} ${it.canonicalAlias.orEmpty()}".toLowerCase(Locale.ROOT)
.let { str ->
explicitContentTerms.all { term -> term !in str }
}
showAllRooms || explicitTermFilter.isValid("${it.name.orEmpty()} ${it.topic.orEmpty()}")
}
setState {