Add tests for pushrule conditions and fix bugs found when making tests
This commit is contained in:
parent
bb9ed4558b
commit
0cdde557a3
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
.idea/
|
||||
gomuks
|
||||
gomuks.exe
|
||||
coverage.out
|
||||
|
682
coverage.html
Normal file
682
coverage.html
Normal file
@ -0,0 +1,682 @@
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<style>
|
||||
body {
|
||||
background: black;
|
||||
color: rgb(80, 80, 80);
|
||||
}
|
||||
body, pre, #legend span {
|
||||
font-family: Menlo, monospace;
|
||||
font-weight: bold;
|
||||
}
|
||||
#topbar {
|
||||
background: black;
|
||||
position: fixed;
|
||||
top: 0; left: 0; right: 0;
|
||||
height: 42px;
|
||||
border-bottom: 1px solid rgb(80, 80, 80);
|
||||
}
|
||||
#content {
|
||||
margin-top: 50px;
|
||||
}
|
||||
#nav, #legend {
|
||||
float: left;
|
||||
margin-left: 10px;
|
||||
}
|
||||
#legend {
|
||||
margin-top: 12px;
|
||||
}
|
||||
#nav {
|
||||
margin-top: 10px;
|
||||
}
|
||||
#legend span {
|
||||
margin: 0 5px;
|
||||
}
|
||||
.cov0 { color: rgb(192, 0, 0) }
|
||||
.cov1 { color: rgb(128, 128, 128) }
|
||||
.cov2 { color: rgb(116, 140, 131) }
|
||||
.cov3 { color: rgb(104, 152, 134) }
|
||||
.cov4 { color: rgb(92, 164, 137) }
|
||||
.cov5 { color: rgb(80, 176, 140) }
|
||||
.cov6 { color: rgb(68, 188, 143) }
|
||||
.cov7 { color: rgb(56, 200, 146) }
|
||||
.cov8 { color: rgb(44, 212, 149) }
|
||||
.cov9 { color: rgb(32, 224, 152) }
|
||||
.cov10 { color: rgb(20, 236, 155) }
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="topbar">
|
||||
<div id="nav">
|
||||
<select id="files">
|
||||
|
||||
<option value="file0">maunium.net/go/gomuks/matrix/pushrules/action.go (51.6%)</option>
|
||||
|
||||
<option value="file1">maunium.net/go/gomuks/matrix/pushrules/condition.go (97.5%)</option>
|
||||
|
||||
<option value="file2">maunium.net/go/gomuks/matrix/pushrules/pushrules.go (50.0%)</option>
|
||||
|
||||
<option value="file3">maunium.net/go/gomuks/matrix/pushrules/rule.go (13.6%)</option>
|
||||
|
||||
<option value="file4">maunium.net/go/gomuks/matrix/pushrules/ruleset.go (52.9%)</option>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
<div id="legend">
|
||||
<span>not tracked</span>
|
||||
|
||||
<span class="cov0">not covered</span>
|
||||
<span class="cov8">covered</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="content">
|
||||
|
||||
<pre class="file" id="file0" style="display: none">// gomuks - A terminal Matrix client written in Go.
|
||||
// Copyright (C) 2018 Tulir Asokan
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package pushrules
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// PushActionType is the type of a PushAction
|
||||
type PushActionType string
|
||||
|
||||
// The allowed push action types as specified in spec section 11.12.1.4.1.
|
||||
const (
|
||||
ActionNotify PushActionType = "notify"
|
||||
ActionDontNotify PushActionType = "dont_notify"
|
||||
ActionCoalesce PushActionType = "coalesce"
|
||||
ActionSetTweak PushActionType = "set_tweak"
|
||||
)
|
||||
|
||||
// PushActionTweak is the type of the tweak in SetTweak push actions.
|
||||
type PushActionTweak string
|
||||
|
||||
// The allowed tweak types as specified in spec section 11.12.1.4.1.1.
|
||||
const (
|
||||
TweakSound PushActionTweak = "sound"
|
||||
TweakHighlight PushActionTweak = "highlight"
|
||||
)
|
||||
|
||||
// PushActionArray is an array of PushActions.
|
||||
type PushActionArray []*PushAction
|
||||
|
||||
// PushActionArrayShould contains the important information parsed from a PushActionArray.
|
||||
type PushActionArrayShould struct {
|
||||
// Whether or not the array contained a Notify, DontNotify or Coalesce action type.
|
||||
NotifySpecified bool
|
||||
// Whether or not the event in question should trigger a notification.
|
||||
Notify bool
|
||||
// Whether or not the event in question should be highlighted.
|
||||
Highlight bool
|
||||
|
||||
// Whether or not the event in question should trigger a sound alert.
|
||||
PlaySound bool
|
||||
// The name of the sound to play if PlaySound is true.
|
||||
SoundName string
|
||||
}
|
||||
|
||||
// Should parses this push action array and returns the relevant details wrapped in a PushActionArrayShould struct.
|
||||
func (actions PushActionArray) Should() (should PushActionArrayShould) <span class="cov8" title="1">{
|
||||
for _, action := range actions </span><span class="cov8" title="1">{
|
||||
switch action.Action </span>{
|
||||
case ActionNotify, ActionCoalesce:<span class="cov0" title="0">
|
||||
should.Notify = true
|
||||
should.NotifySpecified = true</span>
|
||||
case ActionDontNotify:<span class="cov8" title="1">
|
||||
should.Notify = false
|
||||
should.NotifySpecified = true</span>
|
||||
case ActionSetTweak:<span class="cov0" title="0">
|
||||
switch action.Tweak </span>{
|
||||
case TweakHighlight:<span class="cov0" title="0">
|
||||
var ok bool
|
||||
should.Highlight, ok = action.Value.(bool)
|
||||
if !ok </span><span class="cov0" title="0">{
|
||||
// Highlight value not specified, so assume true since the tweak is set.
|
||||
should.Highlight = true
|
||||
}</span>
|
||||
case TweakSound:<span class="cov0" title="0">
|
||||
should.SoundName = action.Value.(string)
|
||||
should.PlaySound = len(should.SoundName) > 0</span>
|
||||
}
|
||||
}
|
||||
}
|
||||
<span class="cov8" title="1">return</span>
|
||||
}
|
||||
|
||||
// PushAction is a single action that should be triggered when receiving a message.
|
||||
type PushAction struct {
|
||||
Action PushActionType
|
||||
Tweak PushActionTweak
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
// UnmarshalJSON parses JSON into this PushAction.
|
||||
//
|
||||
// * If the JSON is a single string, the value is stored in the Action field.
|
||||
// * If the JSON is an object with the set_tweak field, Action will be set to
|
||||
// "set_tweak", Tweak will be set to the value of the set_tweak field and
|
||||
// and Value will be set to the value of the value field.
|
||||
// * In any other case, the function does nothing.
|
||||
func (action *PushAction) UnmarshalJSON(raw []byte) error <span class="cov8" title="1">{
|
||||
var data interface{}
|
||||
|
||||
err := json.Unmarshal(raw, &data)
|
||||
if err != nil </span><span class="cov0" title="0">{
|
||||
return err
|
||||
}</span>
|
||||
|
||||
<span class="cov8" title="1">switch val := data.(type) </span>{
|
||||
case string:<span class="cov8" title="1">
|
||||
action.Action = PushActionType(val)</span>
|
||||
case map[string]interface{}:<span class="cov8" title="1">
|
||||
tweak, ok := val["set_tweak"].(string)
|
||||
if ok </span><span class="cov8" title="1">{
|
||||
action.Action = ActionSetTweak
|
||||
action.Tweak = PushActionTweak(tweak)
|
||||
action.Value, _ = val["value"]
|
||||
}</span>
|
||||
}
|
||||
<span class="cov8" title="1">return nil</span>
|
||||
}
|
||||
|
||||
// MarshalJSON is the reverse of UnmarshalJSON()
|
||||
func (action *PushAction) MarshalJSON() (raw []byte, err error) <span class="cov0" title="0">{
|
||||
if action.Action == ActionSetTweak </span><span class="cov0" title="0">{
|
||||
data := map[string]interface{}{
|
||||
"set_tweak": action.Tweak,
|
||||
"value": action.Value,
|
||||
}
|
||||
return json.Marshal(&data)
|
||||
}</span><span class="cov0" title="0"> else {
|
||||
data := string(action.Action)
|
||||
return json.Marshal(&data)
|
||||
}</span>
|
||||
}
|
||||
</pre>
|
||||
|
||||
<pre class="file" id="file1" style="display: none">// gomuks - A terminal Matrix client written in Go.
|
||||
// Copyright (C) 2018 Tulir Asokan
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package pushrules
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/zyedidia/glob"
|
||||
"maunium.net/go/gomatrix"
|
||||
"maunium.net/go/gomuks/matrix/rooms"
|
||||
)
|
||||
|
||||
// Room is an interface with the functions that are needed for processing room-specific push conditions
|
||||
type Room interface {
|
||||
GetMember(mxid string) *rooms.Member
|
||||
GetMembers() map[string]*rooms.Member
|
||||
GetSessionOwner() *rooms.Member
|
||||
}
|
||||
|
||||
// PushCondKind is the type of a push condition.
|
||||
type PushCondKind string
|
||||
|
||||
// The allowed push condition kinds as specified in section 11.12.1.4.3 of r0.3.0 of the Client-Server API.
|
||||
const (
|
||||
KindEventMatch PushCondKind = "event_match"
|
||||
KindContainsDisplayName PushCondKind = "contains_display_name"
|
||||
KindRoomMemberCount PushCondKind = "room_member_count"
|
||||
)
|
||||
|
||||
// PushCondition wraps a condition that is required for a specific PushRule to be used.
|
||||
type PushCondition struct {
|
||||
// The type of the condition.
|
||||
Kind PushCondKind `json:"kind"`
|
||||
// The dot-separated field of the event to match. Only applicable if kind is EventMatch.
|
||||
Key string `json:"key,omitempty"`
|
||||
// The glob-style pattern to match the field against. Only applicable if kind is EventMatch.
|
||||
Pattern string `json:"pattern,omitempty"`
|
||||
// The condition that needs to be fulfilled for RoomMemberCount-type conditions.
|
||||
// A decimal integer optionally prefixed by ==, <, >, >= or <=. Prefix "==" is assumed if no prefix found.
|
||||
MemberCountCondition string `json:"is,omitempty"`
|
||||
}
|
||||
|
||||
// MemberCountFilterRegex is the regular expression to parse the MemberCountCondition of PushConditions.
|
||||
var MemberCountFilterRegex = regexp.MustCompile("^(==|[<>]=?)?([0-9]+)$")
|
||||
|
||||
// Match checks if this condition is fulfilled for the given event in the given room.
|
||||
func (cond *PushCondition) Match(room Room, event *gomatrix.Event) bool <span class="cov8" title="1">{
|
||||
switch cond.Kind </span>{
|
||||
case KindEventMatch:<span class="cov8" title="1">
|
||||
return cond.matchValue(room, event)</span>
|
||||
case KindContainsDisplayName:<span class="cov8" title="1">
|
||||
return cond.matchDisplayName(room, event)</span>
|
||||
case KindRoomMemberCount:<span class="cov8" title="1">
|
||||
return cond.matchMemberCount(room, event)</span>
|
||||
default:<span class="cov8" title="1">
|
||||
return false</span>
|
||||
}
|
||||
}
|
||||
|
||||
func (cond *PushCondition) matchValue(room Room, event *gomatrix.Event) bool <span class="cov8" title="1">{
|
||||
index := strings.IndexRune(cond.Key, '.')
|
||||
key := cond.Key
|
||||
subkey := ""
|
||||
if index > 0 </span><span class="cov8" title="1">{
|
||||
subkey = key[index+1:]
|
||||
key = key[0:index]
|
||||
}</span>
|
||||
|
||||
<span class="cov8" title="1">pattern, _ := glob.Compile(cond.Pattern)
|
||||
|
||||
switch key </span>{
|
||||
case "type":<span class="cov8" title="1">
|
||||
return pattern.MatchString(event.Type)</span>
|
||||
case "sender":<span class="cov8" title="1">
|
||||
return pattern.MatchString(event.Sender)</span>
|
||||
case "room_id":<span class="cov8" title="1">
|
||||
return pattern.MatchString(event.RoomID)</span>
|
||||
case "state_key":<span class="cov8" title="1">
|
||||
if event.StateKey == nil </span><span class="cov8" title="1">{
|
||||
return cond.Pattern == ""
|
||||
}</span>
|
||||
<span class="cov8" title="1">return pattern.MatchString(*event.StateKey)</span>
|
||||
case "content":<span class="cov8" title="1">
|
||||
val, _ := event.Content[subkey].(string)
|
||||
return pattern.MatchString(val)</span>
|
||||
default:<span class="cov8" title="1">
|
||||
return false</span>
|
||||
}
|
||||
}
|
||||
|
||||
func (cond *PushCondition) matchDisplayName(room Room, event *gomatrix.Event) bool <span class="cov8" title="1">{
|
||||
member := room.GetSessionOwner()
|
||||
if member == nil || member.UserID == event.Sender </span><span class="cov8" title="1">{
|
||||
return false
|
||||
}</span>
|
||||
<span class="cov8" title="1">text, _ := event.Content["body"].(string)
|
||||
return strings.Contains(text, member.DisplayName)</span>
|
||||
}
|
||||
|
||||
func (cond *PushCondition) matchMemberCount(room Room, event *gomatrix.Event) bool <span class="cov8" title="1">{
|
||||
group := MemberCountFilterRegex.FindStringSubmatch(cond.MemberCountCondition)
|
||||
if len(group) != 3 </span><span class="cov8" title="1">{
|
||||
return false
|
||||
}</span>
|
||||
|
||||
<span class="cov8" title="1">operator := group[1]
|
||||
wantedMemberCount, _ := strconv.Atoi(group[2])
|
||||
|
||||
memberCount := len(room.GetMembers())
|
||||
|
||||
switch operator </span>{
|
||||
case "==", "":<span class="cov8" title="1">
|
||||
return memberCount == wantedMemberCount</span>
|
||||
case ">":<span class="cov8" title="1">
|
||||
return memberCount > wantedMemberCount</span>
|
||||
case ">=":<span class="cov8" title="1">
|
||||
return memberCount >= wantedMemberCount</span>
|
||||
case "<":<span class="cov8" title="1">
|
||||
return memberCount < wantedMemberCount</span>
|
||||
case "<=":<span class="cov8" title="1">
|
||||
return memberCount <= wantedMemberCount</span>
|
||||
default:<span class="cov0" title="0">
|
||||
// Should be impossible due to regex.
|
||||
return false</span>
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<pre class="file" id="file2" style="display: none">package pushrules
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
|
||||
"maunium.net/go/gomatrix"
|
||||
)
|
||||
|
||||
// GetPushRules returns the push notification rules for the global scope.
|
||||
func GetPushRules(client *gomatrix.Client) (*PushRuleset, error) <span class="cov0" title="0">{
|
||||
return GetScopedPushRules(client, "global")
|
||||
}</span>
|
||||
|
||||
// GetScopedPushRules returns the push notification rules for the given scope.
|
||||
func GetScopedPushRules(client *gomatrix.Client, scope string) (resp *PushRuleset, err error) <span class="cov0" title="0">{
|
||||
u, _ := url.Parse(client.BuildURL("pushrules", scope))
|
||||
// client.BuildURL returns the URL without a trailing slash, but the pushrules endpoint requires the slash.
|
||||
u.Path += "/"
|
||||
_, err = client.MakeRequest("GET", u.String(), nil, &resp)
|
||||
return
|
||||
}</span>
|
||||
|
||||
// EventToPushRules converts a m.push_rules event to a PushRuleset by passing the data through JSON.
|
||||
func EventToPushRules(event *gomatrix.Event) (*PushRuleset, error) <span class="cov8" title="1">{
|
||||
content, _ := event.Content["global"]
|
||||
raw, err := json.Marshal(content)
|
||||
if err != nil </span><span class="cov0" title="0">{
|
||||
return nil, err
|
||||
}</span>
|
||||
|
||||
<span class="cov8" title="1">ruleset := &PushRuleset{}
|
||||
err = json.Unmarshal(raw, ruleset)
|
||||
if err != nil </span><span class="cov0" title="0">{
|
||||
return nil, err
|
||||
}</span>
|
||||
|
||||
<span class="cov8" title="1">return ruleset, nil</span>
|
||||
}
|
||||
</pre>
|
||||
|
||||
<pre class="file" id="file3" style="display: none">// gomuks - A terminal Matrix client written in Go.
|
||||
// Copyright (C) 2018 Tulir Asokan
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package pushrules
|
||||
|
||||
import (
|
||||
"github.com/zyedidia/glob"
|
||||
"maunium.net/go/gomatrix"
|
||||
)
|
||||
|
||||
type PushRuleCollection interface {
|
||||
GetActions(room Room, event *gomatrix.Event) PushActionArray
|
||||
}
|
||||
|
||||
type PushRuleArray []*PushRule
|
||||
|
||||
func (rules PushRuleArray) setType(typ PushRuleType) PushRuleArray <span class="cov8" title="1">{
|
||||
for _, rule := range rules </span><span class="cov8" title="1">{
|
||||
rule.Type = typ
|
||||
}</span>
|
||||
<span class="cov8" title="1">return rules</span>
|
||||
}
|
||||
|
||||
func (rules PushRuleArray) GetActions(room Room, event *gomatrix.Event) PushActionArray <span class="cov0" title="0">{
|
||||
for _, rule := range rules </span><span class="cov0" title="0">{
|
||||
if !rule.Match(room, event) </span><span class="cov0" title="0">{
|
||||
continue</span>
|
||||
}
|
||||
<span class="cov0" title="0">return rule.Actions</span>
|
||||
}
|
||||
<span class="cov0" title="0">return nil</span>
|
||||
}
|
||||
|
||||
type PushRuleMap struct {
|
||||
Map map[string]*PushRule
|
||||
Type PushRuleType
|
||||
}
|
||||
|
||||
func (rules PushRuleArray) setTypeAndMap(typ PushRuleType) PushRuleMap <span class="cov8" title="1">{
|
||||
data := PushRuleMap{
|
||||
Map: make(map[string]*PushRule),
|
||||
Type: typ,
|
||||
}
|
||||
for _, rule := range rules </span><span class="cov0" title="0">{
|
||||
rule.Type = typ
|
||||
data.Map[rule.RuleID] = rule
|
||||
}</span>
|
||||
<span class="cov8" title="1">return data</span>
|
||||
}
|
||||
|
||||
func (ruleMap PushRuleMap) GetActions(room Room, event *gomatrix.Event) PushActionArray <span class="cov0" title="0">{
|
||||
var rule *PushRule
|
||||
var found bool
|
||||
switch ruleMap.Type </span>{
|
||||
case RoomRule:<span class="cov0" title="0">
|
||||
rule, found = ruleMap.Map[event.RoomID]</span>
|
||||
case SenderRule:<span class="cov0" title="0">
|
||||
rule, found = ruleMap.Map[event.Sender]</span>
|
||||
}
|
||||
<span class="cov0" title="0">if found && rule.Match(room, event) </span><span class="cov0" title="0">{
|
||||
return rule.Actions
|
||||
}</span>
|
||||
<span class="cov0" title="0">return nil</span>
|
||||
}
|
||||
|
||||
func (ruleMap PushRuleMap) unmap() PushRuleArray <span class="cov0" title="0">{
|
||||
array := make(PushRuleArray, len(ruleMap.Map))
|
||||
index := 0
|
||||
for _, rule := range ruleMap.Map </span><span class="cov0" title="0">{
|
||||
array[index] = rule
|
||||
index++
|
||||
}</span>
|
||||
<span class="cov0" title="0">return array</span>
|
||||
}
|
||||
|
||||
type PushRuleType string
|
||||
|
||||
const (
|
||||
OverrideRule PushRuleType = "override"
|
||||
ContentRule PushRuleType = "content"
|
||||
RoomRule PushRuleType = "room"
|
||||
SenderRule PushRuleType = "sender"
|
||||
UnderrideRule PushRuleType = "underride"
|
||||
)
|
||||
|
||||
type PushRule struct {
|
||||
// The type of this rule.
|
||||
Type PushRuleType `json:"-"`
|
||||
// The ID of this rule.
|
||||
// For room-specific rules and user-specific rules, this is the room or user ID (respectively)
|
||||
// For other types of rules, this doesn't affect anything.
|
||||
RuleID string `json:"rule_id"`
|
||||
// The actions this rule should trigger when matched.
|
||||
Actions PushActionArray `json:"actions"`
|
||||
// Whether this is a default rule, or has been set explicitly.
|
||||
Default bool `json:"default"`
|
||||
// Whether or not this push rule is enabled.
|
||||
Enabled bool `json:"enabled"`
|
||||
// The conditions to match in order to trigger this rule.
|
||||
// Only applicable to generic underride/override rules.
|
||||
Conditions []*PushCondition `json:"conditions,omitempty"`
|
||||
// Pattern for content-specific push rules
|
||||
Pattern string `json:"pattern,omitempty"`
|
||||
}
|
||||
|
||||
func (rule *PushRule) Match(room Room, event *gomatrix.Event) bool <span class="cov0" title="0">{
|
||||
if !rule.Enabled </span><span class="cov0" title="0">{
|
||||
return false
|
||||
}</span>
|
||||
<span class="cov0" title="0">switch rule.Type </span>{
|
||||
case OverrideRule, UnderrideRule:<span class="cov0" title="0">
|
||||
return rule.matchConditions(room, event)</span>
|
||||
case ContentRule:<span class="cov0" title="0">
|
||||
return rule.matchPattern(room, event)</span>
|
||||
case RoomRule:<span class="cov0" title="0">
|
||||
return rule.RuleID == event.RoomID</span>
|
||||
case SenderRule:<span class="cov0" title="0">
|
||||
return rule.RuleID == event.Sender</span>
|
||||
default:<span class="cov0" title="0">
|
||||
return false</span>
|
||||
}
|
||||
}
|
||||
|
||||
func (rule *PushRule) matchConditions(room Room, event *gomatrix.Event) bool <span class="cov0" title="0">{
|
||||
for _, cond := range rule.Conditions </span><span class="cov0" title="0">{
|
||||
if !cond.Match(room, event) </span><span class="cov0" title="0">{
|
||||
return false
|
||||
}</span>
|
||||
}
|
||||
<span class="cov0" title="0">return true</span>
|
||||
}
|
||||
|
||||
func (rule *PushRule) matchPattern(room Room, event *gomatrix.Event) bool <span class="cov0" title="0">{
|
||||
pattern, err := glob.Compile(rule.Pattern)
|
||||
if err != nil </span><span class="cov0" title="0">{
|
||||
return false
|
||||
}</span>
|
||||
<span class="cov0" title="0">text, _ := event.Content["body"].(string)
|
||||
return pattern.MatchString(text)</span>
|
||||
}
|
||||
</pre>
|
||||
|
||||
<pre class="file" id="file4" style="display: none">// gomuks - A terminal Matrix client written in Go.
|
||||
// Copyright (C) 2018 Tulir Asokan
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package pushrules
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"maunium.net/go/gomatrix"
|
||||
)
|
||||
|
||||
type PushRuleset struct {
|
||||
Override PushRuleArray
|
||||
Content PushRuleArray
|
||||
Room PushRuleMap
|
||||
Sender PushRuleMap
|
||||
Underride PushRuleArray
|
||||
}
|
||||
|
||||
type rawPushRuleset struct {
|
||||
Override PushRuleArray `json:"override"`
|
||||
Content PushRuleArray `json:"content"`
|
||||
Room PushRuleArray `json:"room"`
|
||||
Sender PushRuleArray `json:"sender"`
|
||||
Underride PushRuleArray `json:"underride"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON parses JSON into this PushRuleset.
|
||||
//
|
||||
// For override, sender and underride push rule arrays, the type is added
|
||||
// to each PushRule and the array is used as-is.
|
||||
//
|
||||
// For room and sender push rule arrays, the type is added to each PushRule
|
||||
// and the array is converted to a map with the rule ID as the key and the
|
||||
// PushRule as the value.
|
||||
func (rs *PushRuleset) UnmarshalJSON(raw []byte) (err error) <span class="cov8" title="1">{
|
||||
data := rawPushRuleset{}
|
||||
err = json.Unmarshal(raw, &data)
|
||||
if err != nil </span><span class="cov0" title="0">{
|
||||
return
|
||||
}</span>
|
||||
|
||||
<span class="cov8" title="1">rs.Override = data.Override.setType(OverrideRule)
|
||||
rs.Content = data.Content.setType(ContentRule)
|
||||
rs.Room = data.Room.setTypeAndMap(RoomRule)
|
||||
rs.Sender = data.Sender.setTypeAndMap(SenderRule)
|
||||
rs.Underride = data.Underride.setType(UnderrideRule)
|
||||
return</span>
|
||||
}
|
||||
|
||||
// MarshalJSON is the reverse of UnmarshalJSON()
|
||||
func (rs *PushRuleset) MarshalJSON() ([]byte, error) <span class="cov0" title="0">{
|
||||
data := rawPushRuleset{
|
||||
Override: rs.Override,
|
||||
Content: rs.Content,
|
||||
Room: rs.Room.unmap(),
|
||||
Sender: rs.Sender.unmap(),
|
||||
Underride: rs.Underride,
|
||||
}
|
||||
return json.Marshal(&data)
|
||||
}</span>
|
||||
|
||||
// DefaultPushActions is the value returned if none of the rule
|
||||
// collections in a Ruleset match the event given to GetActions()
|
||||
var DefaultPushActions = make(PushActionArray, 0)
|
||||
|
||||
// GetActions matches the given event against all of the push rule
|
||||
// collections in this push ruleset in the order of priority as
|
||||
// specified in spec section 11.12.1.4.
|
||||
func (rs *PushRuleset) GetActions(room Room, event *gomatrix.Event) (match PushActionArray) <span class="cov0" title="0">{
|
||||
// Add push rule collections to array in priority order
|
||||
arrays := []PushRuleCollection{rs.Override, rs.Content, rs.Room, rs.Sender, rs.Underride}
|
||||
// Loop until one of the push rule collections matches the room/event combo.
|
||||
for _, pra := range arrays </span><span class="cov0" title="0">{
|
||||
if match = pra.GetActions(room, event); match != nil </span><span class="cov0" title="0">{
|
||||
// Match found, return it.
|
||||
return
|
||||
}</span>
|
||||
}
|
||||
// No match found, return default actions.
|
||||
<span class="cov0" title="0">return DefaultPushActions</span>
|
||||
}
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
(function() {
|
||||
var files = document.getElementById('files');
|
||||
var visible;
|
||||
files.addEventListener('change', onChange, false);
|
||||
function select(part) {
|
||||
if (visible)
|
||||
visible.style.display = 'none';
|
||||
visible = document.getElementById(part);
|
||||
if (!visible)
|
||||
return;
|
||||
files.value = part;
|
||||
visible.style.display = 'block';
|
||||
location.hash = part;
|
||||
}
|
||||
function onChange() {
|
||||
select(files.value);
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
if (location.hash != "") {
|
||||
select(location.hash.substr(1));
|
||||
}
|
||||
if (!visible) {
|
||||
select("file0");
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</html>
|
@ -26,6 +26,13 @@ import (
|
||||
"maunium.net/go/gomuks/matrix/rooms"
|
||||
)
|
||||
|
||||
// Room is an interface with the functions that are needed for processing room-specific push conditions
|
||||
type Room interface {
|
||||
GetMember(mxid string) *rooms.Member
|
||||
GetMembers() map[string]*rooms.Member
|
||||
GetSessionOwner() *rooms.Member
|
||||
}
|
||||
|
||||
// PushCondKind is the type of a push condition.
|
||||
type PushCondKind string
|
||||
|
||||
@ -53,7 +60,7 @@ type PushCondition struct {
|
||||
var MemberCountFilterRegex = regexp.MustCompile("^(==|[<>]=?)?([0-9]+)$")
|
||||
|
||||
// Match checks if this condition is fulfilled for the given event in the given room.
|
||||
func (cond *PushCondition) Match(room *rooms.Room, event *gomatrix.Event) bool {
|
||||
func (cond *PushCondition) Match(room Room, event *gomatrix.Event) bool {
|
||||
switch cond.Kind {
|
||||
case KindEventMatch:
|
||||
return cond.matchValue(room, event)
|
||||
@ -66,7 +73,7 @@ func (cond *PushCondition) Match(room *rooms.Room, event *gomatrix.Event) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (cond *PushCondition) matchValue(room *rooms.Room, event *gomatrix.Event) bool {
|
||||
func (cond *PushCondition) matchValue(room Room, event *gomatrix.Event) bool {
|
||||
index := strings.IndexRune(cond.Key, '.')
|
||||
key := cond.Key
|
||||
subkey := ""
|
||||
@ -75,10 +82,7 @@ func (cond *PushCondition) matchValue(room *rooms.Room, event *gomatrix.Event) b
|
||||
key = key[0:index]
|
||||
}
|
||||
|
||||
pattern, err := glob.Compile(cond.Pattern)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
pattern, _ := glob.Compile(cond.Pattern)
|
||||
|
||||
switch key {
|
||||
case "type":
|
||||
@ -100,48 +104,39 @@ func (cond *PushCondition) matchValue(room *rooms.Room, event *gomatrix.Event) b
|
||||
}
|
||||
}
|
||||
|
||||
func (cond *PushCondition) matchDisplayName(room *rooms.Room, event *gomatrix.Event) bool {
|
||||
member := room.GetMember(room.SessionUserID)
|
||||
if member == nil {
|
||||
func (cond *PushCondition) matchDisplayName(room Room, event *gomatrix.Event) bool {
|
||||
member := room.GetSessionOwner()
|
||||
if member == nil || member.UserID == event.Sender {
|
||||
return false
|
||||
}
|
||||
text, _ := event.Content["body"].(string)
|
||||
return strings.Contains(text, member.DisplayName)
|
||||
}
|
||||
|
||||
func (cond *PushCondition) matchMemberCount(room *rooms.Room, event *gomatrix.Event) bool {
|
||||
groupGroups := MemberCountFilterRegex.FindAllStringSubmatch(cond.MemberCountCondition, -1)
|
||||
if len(groupGroups) != 1 {
|
||||
func (cond *PushCondition) matchMemberCount(room Room, event *gomatrix.Event) bool {
|
||||
group := MemberCountFilterRegex.FindStringSubmatch(cond.MemberCountCondition)
|
||||
if len(group) != 3 {
|
||||
return false
|
||||
}
|
||||
|
||||
operator := "=="
|
||||
wantedMemberCount := 0
|
||||
|
||||
group := groupGroups[0]
|
||||
if len(group) == 0 {
|
||||
return false
|
||||
} else if len(group) == 1 {
|
||||
wantedMemberCount, _ = strconv.Atoi(group[0])
|
||||
} else {
|
||||
operator = group[0]
|
||||
wantedMemberCount, _ = strconv.Atoi(group[1])
|
||||
}
|
||||
operator := group[1]
|
||||
wantedMemberCount, _ := strconv.Atoi(group[2])
|
||||
|
||||
memberCount := len(room.GetMembers())
|
||||
|
||||
switch operator {
|
||||
case "==":
|
||||
return wantedMemberCount == memberCount
|
||||
case "==", "":
|
||||
return memberCount == wantedMemberCount
|
||||
case ">":
|
||||
return wantedMemberCount > memberCount
|
||||
return memberCount > wantedMemberCount
|
||||
case ">=":
|
||||
return wantedMemberCount >= memberCount
|
||||
return memberCount >= wantedMemberCount
|
||||
case "<":
|
||||
return wantedMemberCount < memberCount
|
||||
return memberCount < wantedMemberCount
|
||||
case "<=":
|
||||
return wantedMemberCount <= memberCount
|
||||
return memberCount <= wantedMemberCount
|
||||
default:
|
||||
// Should be impossible due to regex.
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
59
matrix/pushrules/condition_displayname_test.go
Normal file
59
matrix/pushrules/condition_displayname_test.go
Normal file
@ -0,0 +1,59 @@
|
||||
// gomuks - A terminal Matrix client written in Go.
|
||||
// Copyright (C) 2018 Tulir Asokan
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package pushrules_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPushCondition_Match_DisplayName(t *testing.T) {
|
||||
event := newFakeEvent("m.room.message", map[string]interface{}{
|
||||
"msgtype": "m.text",
|
||||
"body": "tulir: test mention",
|
||||
})
|
||||
event.Sender = "@someone_else:matrix.org"
|
||||
assert.True(t, displaynamePushCondition.Match(displaynameTestRoom, event))
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_DisplayName_Fail(t *testing.T) {
|
||||
event := newFakeEvent("m.room.message", map[string]interface{}{
|
||||
"msgtype": "m.text",
|
||||
"body": "not a mention",
|
||||
})
|
||||
event.Sender = "@someone_else:matrix.org"
|
||||
assert.False(t, displaynamePushCondition.Match(displaynameTestRoom, event))
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_DisplayName_CantHighlightSelf(t *testing.T) {
|
||||
event := newFakeEvent("m.room.message", map[string]interface{}{
|
||||
"msgtype": "m.text",
|
||||
"body": "tulir: I can't highlight myself",
|
||||
})
|
||||
assert.False(t, displaynamePushCondition.Match(displaynameTestRoom, event))
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_DisplayName_FailsOnEmptyRoom(t *testing.T) {
|
||||
emptyRoom := newFakeRoom(0)
|
||||
event := newFakeEvent("m.room.message", map[string]interface{}{
|
||||
"msgtype": "m.text",
|
||||
"body": "tulir: this room doesn't have the owner Member available, so it fails.",
|
||||
})
|
||||
event.Sender = "@someone_else:matrix.org"
|
||||
assert.False(t, displaynamePushCondition.Match(emptyRoom, event))
|
||||
}
|
85
matrix/pushrules/condition_eventmatch_test.go
Normal file
85
matrix/pushrules/condition_eventmatch_test.go
Normal file
@ -0,0 +1,85 @@
|
||||
// gomuks - A terminal Matrix client written in Go.
|
||||
// Copyright (C) 2018 Tulir Asokan
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package pushrules_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPushCondition_Match_KindEvent_MsgType(t *testing.T) {
|
||||
condition := newMatchPushCondition("content.msgtype", "m.emote")
|
||||
event := newFakeEvent("m.room.message", map[string]interface{}{
|
||||
"msgtype": "m.emote",
|
||||
"body": "tests gomuks pushconditions",
|
||||
})
|
||||
assert.True(t, condition.Match(blankTestRoom, event))
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_KindEvent_MsgType_Fail(t *testing.T) {
|
||||
condition := newMatchPushCondition("content.msgtype", "m.emote")
|
||||
|
||||
event := newFakeEvent("m.room.message", map[string]interface{}{
|
||||
"msgtype": "m.text",
|
||||
"body": "I'm testing gomuks pushconditions",
|
||||
})
|
||||
assert.False(t, condition.Match(blankTestRoom, event))
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_KindEvent_EventType(t *testing.T) {
|
||||
condition := newMatchPushCondition("type", "m.room.foo")
|
||||
event := newFakeEvent("m.room.foo", map[string]interface{}{})
|
||||
assert.True(t, condition.Match(blankTestRoom, event))
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_KindEvent_Sender_Fail(t *testing.T) {
|
||||
condition := newMatchPushCondition("sender", "@foo:maunium.net")
|
||||
event := newFakeEvent("m.room.foo", map[string]interface{}{})
|
||||
assert.False(t, condition.Match(blankTestRoom, event))
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_KindEvent_RoomID(t *testing.T) {
|
||||
condition := newMatchPushCondition("room_id", "!fakeroom:maunium.net")
|
||||
event := newFakeEvent("", map[string]interface{}{})
|
||||
assert.True(t, condition.Match(blankTestRoom, event))
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_KindEvent_BlankStateKey(t *testing.T) {
|
||||
condition := newMatchPushCondition("state_key", "")
|
||||
event := newFakeEvent("m.room.foo", map[string]interface{}{})
|
||||
assert.True(t, condition.Match(blankTestRoom, event))
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_KindEvent_BlankStateKey_Fail(t *testing.T) {
|
||||
condition := newMatchPushCondition("state_key", "not blank")
|
||||
event := newFakeEvent("m.room.foo", map[string]interface{}{})
|
||||
assert.False(t, condition.Match(blankTestRoom, event))
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_KindEvent_NonBlankStateKey(t *testing.T) {
|
||||
condition := newMatchPushCondition("state_key", "*:maunium.net")
|
||||
event := newFakeEvent("m.room.foo", map[string]interface{}{})
|
||||
event.StateKey = &event.Sender
|
||||
assert.True(t, condition.Match(blankTestRoom, event))
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_KindEvent_UnknownKey(t *testing.T) {
|
||||
condition := newMatchPushCondition("non-existent key", "doesn't affect anything")
|
||||
event := newFakeEvent("m.room.foo", map[string]interface{}{})
|
||||
assert.False(t, condition.Match(blankTestRoom, event))
|
||||
}
|
71
matrix/pushrules/condition_membercount_test.go
Normal file
71
matrix/pushrules/condition_membercount_test.go
Normal file
@ -0,0 +1,71 @@
|
||||
// gomuks - A terminal Matrix client written in Go.
|
||||
// Copyright (C) 2018 Tulir Asokan
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package pushrules_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPushCondition_Match_KindMemberCount_OneToOne_ImplicitPrefix(t *testing.T) {
|
||||
condition := newCountPushCondition("2")
|
||||
room := newFakeRoom(2)
|
||||
assert.True(t, condition.Match(room, countConditionTestEvent))
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_KindMemberCount_OneToOne_ExplicitPrefix(t *testing.T) {
|
||||
condition := newCountPushCondition("==2")
|
||||
room := newFakeRoom(2)
|
||||
assert.True(t, condition.Match(room, countConditionTestEvent))
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_KindMemberCount_BigRoom(t *testing.T) {
|
||||
condition := newCountPushCondition(">200")
|
||||
room := newFakeRoom(201)
|
||||
assert.True(t, condition.Match(room, countConditionTestEvent))
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_KindMemberCount_BigRoom_Fail(t *testing.T) {
|
||||
condition := newCountPushCondition(">=200")
|
||||
room := newFakeRoom(199)
|
||||
assert.False(t, condition.Match(room, countConditionTestEvent))
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_KindMemberCount_SmallRoom(t *testing.T) {
|
||||
condition := newCountPushCondition("<10")
|
||||
room := newFakeRoom(9)
|
||||
assert.True(t, condition.Match(room, countConditionTestEvent))
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_KindMemberCount_SmallRoom_Fail(t *testing.T) {
|
||||
condition := newCountPushCondition("<=10")
|
||||
room := newFakeRoom(11)
|
||||
assert.False(t, condition.Match(room, countConditionTestEvent))
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_KindMemberCount_InvalidPrefix(t *testing.T) {
|
||||
condition := newCountPushCondition("??10")
|
||||
room := newFakeRoom(11)
|
||||
assert.False(t, condition.Match(room, countConditionTestEvent))
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_KindMemberCount_InvalidCondition(t *testing.T) {
|
||||
condition := newCountPushCondition("foobar")
|
||||
room := newFakeRoom(1)
|
||||
assert.False(t, condition.Match(room, countConditionTestEvent))
|
||||
}
|
134
matrix/pushrules/condition_test.go
Normal file
134
matrix/pushrules/condition_test.go
Normal file
@ -0,0 +1,134 @@
|
||||
// gomuks - A terminal Matrix client written in Go.
|
||||
// Copyright (C) 2018 Tulir Asokan
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package pushrules_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"maunium.net/go/gomatrix"
|
||||
"maunium.net/go/gomuks/matrix/pushrules"
|
||||
"maunium.net/go/gomuks/matrix/rooms"
|
||||
)
|
||||
|
||||
var (
|
||||
blankTestRoom *rooms.Room
|
||||
displaynameTestRoom pushrules.Room
|
||||
|
||||
countConditionTestEvent *gomatrix.Event
|
||||
|
||||
displaynamePushCondition *pushrules.PushCondition
|
||||
)
|
||||
|
||||
func init() {
|
||||
blankTestRoom = rooms.NewRoom("!fakeroom:maunium.net", "@tulir:maunium.net")
|
||||
|
||||
countConditionTestEvent = &gomatrix.Event{
|
||||
Sender: "@tulir:maunium.net",
|
||||
Type: "m.room.message",
|
||||
Timestamp: 1523791120,
|
||||
ID: "$123:maunium.net",
|
||||
RoomID: "!fakeroom:maunium.net",
|
||||
Content: map[string]interface{}{
|
||||
"msgtype": "m.text",
|
||||
"body": "test",
|
||||
},
|
||||
}
|
||||
|
||||
displaynameTestRoom = newFakeRoom(4)
|
||||
displaynamePushCondition = &pushrules.PushCondition{
|
||||
Kind: pushrules.KindContainsDisplayName,
|
||||
}
|
||||
}
|
||||
|
||||
func newFakeEvent(evtType string, content map[string]interface{}) *gomatrix.Event {
|
||||
return &gomatrix.Event{
|
||||
Sender: "@tulir:maunium.net",
|
||||
Type: evtType,
|
||||
Timestamp: 1523791120,
|
||||
ID: "$123:maunium.net",
|
||||
RoomID: "!fakeroom:maunium.net",
|
||||
Content: content,
|
||||
}
|
||||
}
|
||||
|
||||
func newCountPushCondition(condition string) *pushrules.PushCondition {
|
||||
return &pushrules.PushCondition{
|
||||
Kind: pushrules.KindRoomMemberCount,
|
||||
MemberCountCondition: condition,
|
||||
}
|
||||
}
|
||||
|
||||
func newMatchPushCondition(key, pattern string) *pushrules.PushCondition {
|
||||
return &pushrules.PushCondition{
|
||||
Kind: pushrules.KindEventMatch,
|
||||
Key: key,
|
||||
Pattern: pattern,
|
||||
}
|
||||
}
|
||||
|
||||
func TestPushCondition_Match_InvalidKind(t *testing.T) {
|
||||
condition := &pushrules.PushCondition{
|
||||
Kind: pushrules.PushCondKind("invalid"),
|
||||
}
|
||||
event := newFakeEvent("m.room.foobar", map[string]interface{}{})
|
||||
assert.False(t, condition.Match(blankTestRoom, event))
|
||||
}
|
||||
|
||||
type FakeRoom struct {
|
||||
members map[string]*rooms.Member
|
||||
owner string
|
||||
}
|
||||
|
||||
func newFakeRoom(memberCount int) *FakeRoom {
|
||||
room := &FakeRoom{
|
||||
owner: "@tulir:maunium.net",
|
||||
members: make(map[string]*rooms.Member),
|
||||
}
|
||||
|
||||
if memberCount >= 1 {
|
||||
room.members["@tulir:maunium.net"] = &rooms.Member{
|
||||
UserID: "@tulir:maunium.net",
|
||||
Membership: rooms.MembershipJoin,
|
||||
DisplayName: "tulir",
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < memberCount-1; i++ {
|
||||
mxid := fmt.Sprintf("@extrauser_%d:matrix.org", i)
|
||||
room.members[mxid] = &rooms.Member{
|
||||
UserID: mxid,
|
||||
Membership: rooms.MembershipJoin,
|
||||
DisplayName: fmt.Sprintf("Extra User %d", i),
|
||||
}
|
||||
}
|
||||
|
||||
return room
|
||||
}
|
||||
|
||||
func (fr *FakeRoom) GetMember(mxid string) *rooms.Member {
|
||||
return fr.members[mxid]
|
||||
}
|
||||
|
||||
func (fr *FakeRoom) GetSessionOwner() *rooms.Member {
|
||||
return fr.members[fr.owner]
|
||||
}
|
||||
|
||||
func (fr *FakeRoom) GetMembers() map[string]*rooms.Member {
|
||||
return fr.members
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package pushrules
|
||||
package pushrules_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@ -22,6 +22,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"maunium.net/go/gomatrix"
|
||||
"maunium.net/go/gomuks/matrix/pushrules"
|
||||
)
|
||||
|
||||
var mapExamplePushRules map[string]interface{}
|
||||
@ -37,15 +38,15 @@ func TestEventToPushRules(t *testing.T) {
|
||||
Timestamp: 1523380910,
|
||||
Content: mapExamplePushRules,
|
||||
}
|
||||
pushRuleset, err := EventToPushRules(event)
|
||||
pushRuleset, err := pushrules.EventToPushRules(event)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, pushRuleset)
|
||||
|
||||
assert.IsType(t, pushRuleset.Override, PushRuleArray{})
|
||||
assert.IsType(t, pushRuleset.Content, PushRuleArray{})
|
||||
assert.IsType(t, pushRuleset.Room, PushRuleMap{})
|
||||
assert.IsType(t, pushRuleset.Sender, PushRuleMap{})
|
||||
assert.IsType(t, pushRuleset.Underride, PushRuleArray{})
|
||||
assert.IsType(t, pushRuleset.Override, pushrules.PushRuleArray{})
|
||||
assert.IsType(t, pushRuleset.Content, pushrules.PushRuleArray{})
|
||||
assert.IsType(t, pushRuleset.Room, pushrules.PushRuleMap{})
|
||||
assert.IsType(t, pushRuleset.Sender, pushrules.PushRuleMap{})
|
||||
assert.IsType(t, pushRuleset.Underride, pushrules.PushRuleArray{})
|
||||
assert.Len(t, pushRuleset.Override, 2)
|
||||
assert.Len(t, pushRuleset.Content, 1)
|
||||
assert.Empty(t, pushRuleset.Room.Map)
|
||||
|
@ -19,11 +19,10 @@ package pushrules
|
||||
import (
|
||||
"github.com/zyedidia/glob"
|
||||
"maunium.net/go/gomatrix"
|
||||
"maunium.net/go/gomuks/matrix/rooms"
|
||||
)
|
||||
|
||||
type PushRuleCollection interface {
|
||||
GetActions(room *rooms.Room, event *gomatrix.Event) PushActionArray
|
||||
GetActions(room Room, event *gomatrix.Event) PushActionArray
|
||||
}
|
||||
|
||||
type PushRuleArray []*PushRule
|
||||
@ -35,7 +34,7 @@ func (rules PushRuleArray) setType(typ PushRuleType) PushRuleArray {
|
||||
return rules
|
||||
}
|
||||
|
||||
func (rules PushRuleArray) GetActions(room *rooms.Room, event *gomatrix.Event) PushActionArray {
|
||||
func (rules PushRuleArray) GetActions(room Room, event *gomatrix.Event) PushActionArray {
|
||||
for _, rule := range rules {
|
||||
if !rule.Match(room, event) {
|
||||
continue
|
||||
@ -62,7 +61,7 @@ func (rules PushRuleArray) setTypeAndMap(typ PushRuleType) PushRuleMap {
|
||||
return data
|
||||
}
|
||||
|
||||
func (ruleMap PushRuleMap) GetActions(room *rooms.Room, event *gomatrix.Event) PushActionArray {
|
||||
func (ruleMap PushRuleMap) GetActions(room Room, event *gomatrix.Event) PushActionArray {
|
||||
var rule *PushRule
|
||||
var found bool
|
||||
switch ruleMap.Type {
|
||||
@ -117,7 +116,7 @@ type PushRule struct {
|
||||
Pattern string `json:"pattern,omitempty"`
|
||||
}
|
||||
|
||||
func (rule *PushRule) Match(room *rooms.Room, event *gomatrix.Event) bool {
|
||||
func (rule *PushRule) Match(room Room, event *gomatrix.Event) bool {
|
||||
if !rule.Enabled {
|
||||
return false
|
||||
}
|
||||
@ -135,7 +134,7 @@ func (rule *PushRule) Match(room *rooms.Room, event *gomatrix.Event) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (rule *PushRule) matchConditions(room *rooms.Room, event *gomatrix.Event) bool {
|
||||
func (rule *PushRule) matchConditions(room Room, event *gomatrix.Event) bool {
|
||||
for _, cond := range rule.Conditions {
|
||||
if !cond.Match(room, event) {
|
||||
return false
|
||||
@ -144,7 +143,7 @@ func (rule *PushRule) matchConditions(room *rooms.Room, event *gomatrix.Event) b
|
||||
return true
|
||||
}
|
||||
|
||||
func (rule *PushRule) matchPattern(room *rooms.Room, event *gomatrix.Event) bool {
|
||||
func (rule *PushRule) matchPattern(room Room, event *gomatrix.Event) bool {
|
||||
pattern, err := glob.Compile(rule.Pattern)
|
||||
if err != nil {
|
||||
return false
|
||||
|
@ -20,7 +20,6 @@ import (
|
||||
"encoding/json"
|
||||
|
||||
"maunium.net/go/gomatrix"
|
||||
"maunium.net/go/gomuks/matrix/rooms"
|
||||
)
|
||||
|
||||
type PushRuleset struct {
|
||||
@ -81,7 +80,7 @@ var DefaultPushActions = make(PushActionArray, 0)
|
||||
// GetActions matches the given event against all of the push rule
|
||||
// collections in this push ruleset in the order of priority as
|
||||
// specified in spec section 11.12.1.4.
|
||||
func (rs *PushRuleset) GetActions(room *rooms.Room, event *gomatrix.Event) (match PushActionArray) {
|
||||
func (rs *PushRuleset) GetActions(room Room, event *gomatrix.Event) (match PushActionArray) {
|
||||
// Add push rule collections to array in priority order
|
||||
arrays := []PushRuleCollection{rs.Override, rs.Content, rs.Room, rs.Sender, rs.Underride}
|
||||
// Loop until one of the push rule collections matches the room/event combo.
|
||||
|
Loading…
Reference in New Issue
Block a user