mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-25 02:45:53 +03:00
Merge pull request #6457 from deepbluev7/nico/fix-at-room
Implement the current spec for event match conditions
This commit is contained in:
commit
48641769d9
6 changed files with 47 additions and 30 deletions
1
changelog.d/6457.bugfix
Normal file
1
changelog.d/6457.bugfix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Fix that replies to @roomba would be highlighted as a room ping. Contributed by Nico.
|
|
@ -17,8 +17,6 @@ package org.matrix.android.sdk.api.session.pushrules
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.session.events.model.Event
|
import org.matrix.android.sdk.api.session.events.model.Event
|
||||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
import org.matrix.android.sdk.internal.util.caseInsensitiveFind
|
|
||||||
import org.matrix.android.sdk.internal.util.hasSpecialGlobChar
|
|
||||||
import org.matrix.android.sdk.internal.util.simpleGlobToRegExp
|
import org.matrix.android.sdk.internal.util.simpleGlobToRegExp
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
|
@ -31,18 +29,14 @@ class EventMatchCondition(
|
||||||
* The glob-style pattern to match against. Patterns with no special glob characters should
|
* The glob-style pattern to match against. Patterns with no special glob characters should
|
||||||
* be treated as having asterisks prepended and appended when testing the condition.
|
* be treated as having asterisks prepended and appended when testing the condition.
|
||||||
*/
|
*/
|
||||||
val pattern: String,
|
val pattern: String
|
||||||
/**
|
|
||||||
* true to match only words. In this case pattern will not be considered as a glob
|
|
||||||
*/
|
|
||||||
val wordsOnly: Boolean
|
|
||||||
) : Condition {
|
) : Condition {
|
||||||
|
|
||||||
override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean {
|
override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean {
|
||||||
return conditionResolver.resolveEventMatchCondition(event, this)
|
return conditionResolver.resolveEventMatchCondition(event, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun technicalDescription() = "'$key' matches '$pattern', words only '$wordsOnly'"
|
override fun technicalDescription() = "'$key' matches '$pattern'"
|
||||||
|
|
||||||
fun isSatisfied(event: Event): Boolean {
|
fun isSatisfied(event: Event): Boolean {
|
||||||
// TODO encrypted events?
|
// TODO encrypted events?
|
||||||
|
@ -50,21 +44,28 @@ class EventMatchCondition(
|
||||||
?: return false
|
?: return false
|
||||||
val value = extractField(rawJson, key) ?: return false
|
val value = extractField(rawJson, key) ?: return false
|
||||||
|
|
||||||
// Patterns with no special glob characters should be treated as having asterisks prepended
|
// The match is performed case-insensitively, and must match the entire value of
|
||||||
// and appended when testing the condition.
|
// the event field given by `key` (though see below regarding `content.body`). The
|
||||||
|
// exact meaning of "case insensitive" is defined by the implementation of the
|
||||||
|
// homeserver.
|
||||||
|
//
|
||||||
|
// As a special case, if `key` is `content.body`, then `pattern` must instead
|
||||||
|
// match any substring of the value of the property which starts and ends at a
|
||||||
|
// word boundary.
|
||||||
return try {
|
return try {
|
||||||
if (wordsOnly) {
|
if (key == "content.body") {
|
||||||
value.caseInsensitiveFind(pattern)
|
val modPattern = if (pattern.startsWith("*") && pattern.endsWith("*")) {
|
||||||
} else {
|
|
||||||
val modPattern = if (pattern.hasSpecialGlobChar()) {
|
|
||||||
// Regex.containsMatchIn() is way faster without leading and trailing
|
// Regex.containsMatchIn() is way faster without leading and trailing
|
||||||
// stars, that don't make any difference for the evaluation result
|
// stars, that don't make any difference for the evaluation result
|
||||||
pattern.removePrefix("*").removeSuffix("*").simpleGlobToRegExp()
|
pattern.removePrefix("*").removeSuffix("*").simpleGlobToRegExp()
|
||||||
} else {
|
} else {
|
||||||
pattern.simpleGlobToRegExp()
|
"(\\W|^)" + pattern.simpleGlobToRegExp() + "(\\W|$)"
|
||||||
}
|
}
|
||||||
val regex = Regex(modPattern, RegexOption.DOT_MATCHES_ALL)
|
val regex = Regex(modPattern, setOf(RegexOption.DOT_MATCHES_ALL, RegexOption.IGNORE_CASE))
|
||||||
regex.containsMatchIn(value)
|
regex.containsMatchIn(value)
|
||||||
|
} else {
|
||||||
|
val regex = Regex(pattern.simpleGlobToRegExp(), setOf(RegexOption.DOT_MATCHES_ALL, RegexOption.IGNORE_CASE))
|
||||||
|
regex.matches(value)
|
||||||
}
|
}
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
// e.g PatternSyntaxException
|
// e.g PatternSyntaxException
|
||||||
|
|
|
@ -22,7 +22,6 @@ import org.matrix.android.sdk.api.session.pushrules.ContainsDisplayNameCondition
|
||||||
import org.matrix.android.sdk.api.session.pushrules.EventMatchCondition
|
import org.matrix.android.sdk.api.session.pushrules.EventMatchCondition
|
||||||
import org.matrix.android.sdk.api.session.pushrules.Kind
|
import org.matrix.android.sdk.api.session.pushrules.Kind
|
||||||
import org.matrix.android.sdk.api.session.pushrules.RoomMemberCountCondition
|
import org.matrix.android.sdk.api.session.pushrules.RoomMemberCountCondition
|
||||||
import org.matrix.android.sdk.api.session.pushrules.RuleIds
|
|
||||||
import org.matrix.android.sdk.api.session.pushrules.SenderNotificationPermissionCondition
|
import org.matrix.android.sdk.api.session.pushrules.SenderNotificationPermissionCondition
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
|
@ -59,11 +58,11 @@ data class PushCondition(
|
||||||
val iz: String? = null
|
val iz: String? = null
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun asExecutableCondition(rule: PushRule): Condition? {
|
fun asExecutableCondition(): Condition? {
|
||||||
return when (Kind.fromString(kind)) {
|
return when (Kind.fromString(kind)) {
|
||||||
Kind.EventMatch -> {
|
Kind.EventMatch -> {
|
||||||
if (key != null && pattern != null) {
|
if (key != null && pattern != null) {
|
||||||
EventMatchCondition(key, pattern, rule.ruleId == RuleIds.RULE_ID_CONTAIN_USER_NAME)
|
EventMatchCondition(key, pattern)
|
||||||
} else {
|
} else {
|
||||||
Timber.e("Malformed Event match condition")
|
Timber.e("Malformed Event match condition")
|
||||||
null
|
null
|
||||||
|
|
|
@ -28,7 +28,7 @@ internal class PushRuleFinder @Inject constructor(
|
||||||
return rules.firstOrNull { rule ->
|
return rules.firstOrNull { rule ->
|
||||||
// All conditions must hold true for an event in order to apply the action for the event.
|
// All conditions must hold true for an event in order to apply the action for the event.
|
||||||
rule.enabled && rule.conditions?.all {
|
rule.enabled && rule.conditions?.all {
|
||||||
it.asExecutableCondition(rule)?.isSatisfied(event, conditionResolver) ?: false
|
it.asExecutableCondition()?.isSatisfied(event, conditionResolver) ?: false
|
||||||
} ?: false
|
} ?: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ class PushRulesConditionTest : MatrixTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test_eventmatch_type_condition() {
|
fun test_eventmatch_type_condition() {
|
||||||
val condition = EventMatchCondition("type", "m.room.message", false)
|
val condition = EventMatchCondition("type", "m.room.message")
|
||||||
|
|
||||||
val simpleTextEvent = createSimpleTextEvent("Yo wtf?")
|
val simpleTextEvent = createSimpleTextEvent("Yo wtf?")
|
||||||
|
|
||||||
|
@ -67,12 +67,12 @@ class PushRulesConditionTest : MatrixTest {
|
||||||
)
|
)
|
||||||
|
|
||||||
assert(condition.isSatisfied(simpleTextEvent))
|
assert(condition.isSatisfied(simpleTextEvent))
|
||||||
assert(!condition.isSatisfied(simpleRoomMemberEvent))
|
assertFalse(condition.isSatisfied(simpleRoomMemberEvent))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test_eventmatch_path_condition() {
|
fun test_eventmatch_path_condition() {
|
||||||
val condition = EventMatchCondition("content.msgtype", "m.text", false)
|
val condition = EventMatchCondition("content.msgtype", "m.text")
|
||||||
|
|
||||||
val simpleTextEvent = createSimpleTextEvent("Yo wtf?")
|
val simpleTextEvent = createSimpleTextEvent("Yo wtf?")
|
||||||
|
|
||||||
|
@ -89,28 +89,29 @@ class PushRulesConditionTest : MatrixTest {
|
||||||
).toContent(),
|
).toContent(),
|
||||||
originServerTs = 0
|
originServerTs = 0
|
||||||
).apply {
|
).apply {
|
||||||
assert(EventMatchCondition("content.membership", "invite", false).isSatisfied(this))
|
assert(EventMatchCondition("content.membership", "invite").isSatisfied(this))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test_eventmatch_cake_condition() {
|
fun test_eventmatch_cake_condition() {
|
||||||
val condition = EventMatchCondition("content.body", "cake", false)
|
val condition = EventMatchCondition("content.body", "cake")
|
||||||
|
|
||||||
assert(condition.isSatisfied(createSimpleTextEvent("How was the cake?")))
|
assert(condition.isSatisfied(createSimpleTextEvent("How was the cake?")))
|
||||||
assert(condition.isSatisfied(createSimpleTextEvent("Howwasthecake?")))
|
assertFalse(condition.isSatisfied(createSimpleTextEvent("Howwasthecake?")))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test_eventmatch_cakelie_condition() {
|
fun test_eventmatch_cakelie_condition() {
|
||||||
val condition = EventMatchCondition("content.body", "cake*lie", false)
|
val condition = EventMatchCondition("content.body", "cake*lie")
|
||||||
|
|
||||||
assert(condition.isSatisfied(createSimpleTextEvent("How was the cakeisalie?")))
|
assert(condition.isSatisfied(createSimpleTextEvent("How was the cakeisalie?")))
|
||||||
|
assertFalse(condition.isSatisfied(createSimpleTextEvent("How was the notcakeisalie?")))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test_eventmatch_words_only_condition() {
|
fun test_eventmatch_words_only_condition() {
|
||||||
val condition = EventMatchCondition("content.body", "ben", true)
|
val condition = EventMatchCondition("content.body", "ben")
|
||||||
|
|
||||||
assertFalse(condition.isSatisfied(createSimpleTextEvent("benoit")))
|
assertFalse(condition.isSatisfied(createSimpleTextEvent("benoit")))
|
||||||
assertFalse(condition.isSatisfied(createSimpleTextEvent("Hello benoit")))
|
assertFalse(condition.isSatisfied(createSimpleTextEvent("Hello benoit")))
|
||||||
|
@ -124,9 +125,24 @@ class PushRulesConditionTest : MatrixTest {
|
||||||
assert(condition.isSatisfied(createSimpleTextEvent("BEN")))
|
assert(condition.isSatisfied(createSimpleTextEvent("BEN")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_eventmatch_at_room_condition() {
|
||||||
|
val condition = EventMatchCondition("content.body", "@room")
|
||||||
|
|
||||||
|
assertFalse(condition.isSatisfied(createSimpleTextEvent("@roomba")))
|
||||||
|
assertFalse(condition.isSatisfied(createSimpleTextEvent("room benoit")))
|
||||||
|
assertFalse(condition.isSatisfied(createSimpleTextEvent("abc@roomba")))
|
||||||
|
|
||||||
|
assert(condition.isSatisfied(createSimpleTextEvent("@room")))
|
||||||
|
assert(condition.isSatisfied(createSimpleTextEvent("@room, ben")))
|
||||||
|
assert(condition.isSatisfied(createSimpleTextEvent("@ROOM")))
|
||||||
|
assert(condition.isSatisfied(createSimpleTextEvent("Use:@room")))
|
||||||
|
assert(condition.isSatisfied(createSimpleTextEvent("Don't ping @room!")))
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test_notice_condition() {
|
fun test_notice_condition() {
|
||||||
val conditionEqual = EventMatchCondition("content.msgtype", "m.notice", false)
|
val conditionEqual = EventMatchCondition("content.msgtype", "m.notice")
|
||||||
|
|
||||||
Event(
|
Event(
|
||||||
type = "m.room.message",
|
type = "m.room.message",
|
||||||
|
|
|
@ -73,7 +73,7 @@ abstract class PushRuleItem : VectorEpoxyModel<PushRuleItem.Holder>(R.layout.ite
|
||||||
pushRule.conditions?.forEachIndexed { i, condition ->
|
pushRule.conditions?.forEachIndexed { i, condition ->
|
||||||
if (i > 0) description.append("\n")
|
if (i > 0) description.append("\n")
|
||||||
description.append(
|
description.append(
|
||||||
condition.asExecutableCondition(pushRule)?.technicalDescription()
|
condition.asExecutableCondition()?.technicalDescription()
|
||||||
?: "UNSUPPORTED"
|
?: "UNSUPPORTED"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue