diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | coverage.html | 682 |
2 files changed, 1 insertions, 682 deletions
@@ -2,3 +2,4 @@ gomuks gomuks.exe coverage.out +coverage.html diff --git a/coverage.html b/coverage.html deleted file mode 100644 index c3d77dd..0000000 --- a/coverage.html +++ /dev/null @@ -1,682 +0,0 @@ - -<!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> |