683 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			683 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
 | 
						|
<!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>
 |