From 9fd67102ad2cca16c092e23ffd928b77ab08d7e0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 21 Mar 2018 23:29:58 +0200 Subject: Refactoring and godocs --- matrix/pushrules/condition.go | 147 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 matrix/pushrules/condition.go (limited to 'matrix/pushrules/condition.go') diff --git a/matrix/pushrules/condition.go b/matrix/pushrules/condition.go new file mode 100644 index 0000000..ecbf5b2 --- /dev/null +++ b/matrix/pushrules/condition.go @@ -0,0 +1,147 @@ +// 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 . + +package pushrules + +import ( + "regexp" + "strconv" + "strings" + + "github.com/zyedidia/glob" + "maunium.net/go/gomatrix" + "maunium.net/go/gomuks/matrix/room" +) + +// 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 *rooms.Room, event *gomatrix.Event) bool { + switch cond.Kind { + case KindEventMatch: + return cond.matchValue(room, event) + case KindContainsDisplayName: + return cond.matchDisplayName(room, event) + case KindRoomMemberCount: + return cond.matchMemberCount(room, event) + default: + return false + } +} + +func (cond *PushCondition) matchValue(room *rooms.Room, event *gomatrix.Event) bool { + index := strings.IndexRune(cond.Key, '.') + key := cond.Key + subkey := "" + if index > 0 { + subkey = key[index+1:] + key = key[0:index] + } + + pattern, err := glob.Compile(cond.Pattern) + if err != nil { + return false + } + + switch key { + case "type": + return pattern.MatchString(event.Type) + case "sender": + return pattern.MatchString(event.Sender) + case "room_id": + return pattern.MatchString(event.RoomID) + case "state_key": + if event.StateKey == nil { + return cond.Pattern == "" + } + return pattern.MatchString(*event.StateKey) + case "content": + val, _ := event.Content[subkey].(string) + return pattern.MatchString(val) + default: + return false + } +} + +func (cond *PushCondition) matchDisplayName(room *rooms.Room, event *gomatrix.Event) bool { + member := room.GetMember(room.SessionUserID) + if member == nil { + 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 { + 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]) + } + + memberCount := len(room.GetMembers()) + + switch operator { + case "==": + return wantedMemberCount == memberCount + case ">": + return wantedMemberCount > memberCount + case ">=": + return wantedMemberCount >= memberCount + case "<": + return wantedMemberCount < memberCount + case "<=": + return wantedMemberCount <= memberCount + default: + return false + } +} -- cgit v1.2.3