aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--persistence/sessions.go100
-rw-r--r--persistence/sessions_test.go28
-rw-r--r--telegram/commands.go106
-rw-r--r--telegram/handlers.go11
4 files changed, 188 insertions, 57 deletions
diff --git a/persistence/sessions.go b/persistence/sessions.go
index 29c4918..0454d97 100644
--- a/persistence/sessions.go
+++ b/persistence/sessions.go
@@ -3,6 +3,7 @@ package persistence
import (
"github.com/pkg/errors"
"io/ioutil"
+ "sync"
"time"
"dev.narayana.im/narayana/telegabber/yamldb"
@@ -34,16 +35,18 @@ type SessionsMap struct {
// Session is a key-values subtree
type Session struct {
- Login string `yaml:":login"`
- Timezone string `yaml:":timezone"`
- KeepOnline bool `yaml:":keeponline"`
- RawMessages bool `yaml:":rawmessages"`
- AsciiArrows bool `yaml:":asciiarrows"`
- OOBMode bool `yaml:":oobmode"`
- Carbons bool `yaml:":carbons"`
- HideIds bool `yaml:":hideids"`
- Receipts bool `yaml:":receipts"`
- NativeEdits bool `yaml:":nativeedits"`
+ Login string `yaml:":login"`
+ Timezone string `yaml:":timezone"`
+ KeepOnline bool `yaml:":keeponline"`
+ RawMessages bool `yaml:":rawmessages"`
+ AsciiArrows bool `yaml:":asciiarrows"`
+ OOBMode bool `yaml:":oobmode"`
+ Carbons bool `yaml:":carbons"`
+ HideIds bool `yaml:":hideids"`
+ Receipts bool `yaml:":receipts"`
+ NativeEdits bool `yaml:":nativeedits"`
+ IgnoredChats []int64 `yaml:":ignoredchats"`
+ ignoredChatsMap map[int64]bool `yaml:"-"`
}
var configKeys = []string{
@@ -59,14 +62,21 @@ var configKeys = []string{
}
var sessionDB *SessionsYamlDB
+var sessionsLock sync.Mutex
// SessionMarshaller implementation for YamlDB
func SessionMarshaller() ([]byte, error) {
cleanedMap := SessionsMap{}
emptySessionsMap(&cleanedMap)
+ sessionsLock.Lock()
+ defer sessionsLock.Unlock()
for jid, session := range sessionDB.Data.Sessions {
if session.Login != "" {
+ session.IgnoredChats = make([]int64, 0, len(session.ignoredChatsMap))
+ for chatID := range session.ignoredChatsMap {
+ session.IgnoredChats = append(session.IgnoredChats, chatID)
+ }
cleanedMap.Sessions[jid] = session
}
}
@@ -108,6 +118,16 @@ func initYamlDB(path string, dataPtr *SessionsMap) (*SessionsYamlDB, error) {
emptySessionsMap(dataPtr)
}
+ // convert ignored users slice to map
+ for jid, session := range dataPtr.Sessions {
+ session.ignoredChatsMap = make(map[int64]bool)
+ for _, chatID := range session.IgnoredChats {
+ session.ignoredChatsMap[chatID] = true
+ }
+ session.IgnoredChats = nil
+ dataPtr.Sessions[jid] = session
+ }
+
return &SessionsYamlDB{
YamlDB: yamldb.YamlDB{
Path: path,
@@ -119,6 +139,13 @@ func initYamlDB(path string, dataPtr *SessionsMap) (*SessionsYamlDB, error) {
// Get retrieves a session value
func (s *Session) Get(key string) (string, error) {
+ sessionsLock.Lock()
+ defer sessionsLock.Unlock()
+
+ return s.get(key)
+}
+
+func (s *Session) get(key string) (string, error) {
switch key {
case "timezone":
return s.Timezone, nil
@@ -145,9 +172,12 @@ func (s *Session) Get(key string) (string, error) {
// ToMap converts the session to a map
func (s *Session) ToMap() map[string]string {
+ sessionsLock.Lock()
+ defer sessionsLock.Unlock()
+
m := make(map[string]string)
for _, configKey := range configKeys {
- value, _ := s.Get(configKey)
+ value, _ := s.get(configKey)
m[configKey] = value
}
@@ -156,6 +186,9 @@ func (s *Session) ToMap() map[string]string {
// Set sets a session value
func (s *Session) Set(key string, value string) (string, error) {
+ sessionsLock.Lock()
+ defer sessionsLock.Unlock()
+
switch key {
case "timezone":
s.Timezone = value
@@ -232,6 +265,51 @@ func (s *Session) TimezoneToLocation() *time.Location {
return zeroLocation
}
+// IgnoreChat adds a chat id to ignore list, returns false if already ignored
+func (s *Session) IgnoreChat(chatID int64) bool {
+ sessionsLock.Lock()
+ defer sessionsLock.Unlock()
+
+ if s.ignoredChatsMap == nil {
+ s.ignoredChatsMap = make(map[int64]bool)
+ } else if _, ok := s.ignoredChatsMap[chatID]; ok {
+ return false
+ }
+
+ s.ignoredChatsMap[chatID] = true
+ return true
+}
+
+// UnignoreChat removes a chat id from ignore list, returns false if not already ignored
+func (s *Session) UnignoreChat(chatID int64) bool {
+ sessionsLock.Lock()
+ defer sessionsLock.Unlock()
+
+ if s.ignoredChatsMap == nil {
+ return false
+ }
+
+ if _, ok := s.ignoredChatsMap[chatID]; !ok {
+ return false
+ }
+
+ delete(s.ignoredChatsMap, chatID)
+ return true
+}
+
+// IsChatIgnored checks the chat id against the ignore list
+func (s *Session) IsChatIgnored(chatID int64) bool {
+ sessionsLock.Lock()
+ defer sessionsLock.Unlock()
+
+ if s.ignoredChatsMap == nil {
+ return false
+ }
+
+ _, ok := s.ignoredChatsMap[chatID]
+ return ok
+}
+
func fromBool(b bool) string {
if b {
return "true"
diff --git a/persistence/sessions_test.go b/persistence/sessions_test.go
index 0339378..001cfa0 100644
--- a/persistence/sessions_test.go
+++ b/persistence/sessions_test.go
@@ -88,3 +88,31 @@ func TestSessionSetAbsent(t *testing.T) {
t.Error("There shouldn't come a donkey!")
}
}
+
+func TestSessionIgnore(t *testing.T) {
+ session := Session{}
+ if session.IsChatIgnored(3) {
+ t.Error("Shouldn't be ignored yet")
+ }
+ if !session.IgnoreChat(3) {
+ t.Error("Shouldn't have been ignored")
+ }
+ if session.IgnoreChat(3) {
+ t.Error("Shouldn't ignore second time")
+ }
+ if !session.IsChatIgnored(3) {
+ t.Error("Should be ignored already")
+ }
+ if session.IsChatIgnored(-145) {
+ t.Error("Wrong chat is ignored")
+ }
+ if !session.UnignoreChat(3) {
+ t.Error("Should successfully unignore")
+ }
+ if session.UnignoreChat(3) {
+ t.Error("Should unignore second time")
+ }
+ if session.IsChatIgnored(3) {
+ t.Error("Shouldn't be ignored already")
+ }
+}
diff --git a/telegram/commands.go b/telegram/commands.go
index 039798f..397ba91 100644
--- a/telegram/commands.go
+++ b/telegram/commands.go
@@ -94,8 +94,8 @@ var chatCommands = map[string]command{
"invite": command{1, []string{"id or @username"}, "add user to current chat", &notForPM},
"link": command{0, []string{}, "get invite link for current chat", &notForPM},
"kick": command{1, []string{"id or @username"}, "remove user from current chat", &notForPM},
- "mute": command{1, []string{"id or @username", "hours"}, "mute user in current chat", &notForPMAndBasic},
- "unmute": command{1, []string{"id or @username"}, "unrestrict user from current chat", &notForPMAndBasic},
+ "mute": command{0, []string{"id or @username", "hours"}, "mute the whole chat or a user in current chat", &notForPMAndBasic},
+ "unmute": command{0, []string{"id or @username"}, "unmute the whole chat or a user in the current chat", &notForPMAndBasic},
"ban": command{1, []string{"id or @username", "hours"}, "restrict @username from current chat for [hours] or forever", &notForPM},
"unban": command{1, []string{"id or @username"}, "unbans @username in current chat (and devotes from admins)", &notForPM},
"promote": command{1, []string{"id or @username", "title"}, "promote user to admin in current chat", &notForPM},
@@ -847,57 +847,71 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool,
if err != nil {
return err.Error(), true, false
}
- // mute @username [n hours]
+ // mute [@username [n hours]]
case "mute":
- contact, _, err := c.GetContactByUsername(args[0])
- if err != nil {
- return err.Error(), true, false
- }
- if contact == nil {
- return "Contact not found", true, false
- }
-
- var hours int64
- if len(args) > 1 {
- hours, err = strconv.ParseInt(args[1], 10, 32)
+ if len(args) > 0 {
+ contact, _, err := c.GetContactByUsername(args[0])
if err != nil {
- return "Invalid number of hours", true, false
+ return err.Error(), true, false
+ }
+ if contact == nil {
+ return "Contact not found", true, false
}
- }
- _, err = c.client.SetChatMemberStatus(&client.SetChatMemberStatusRequest{
- ChatId: chatID,
- MemberId: &client.MessageSenderUser{UserId: contact.Id},
- Status: &client.ChatMemberStatusRestricted{
- IsMember: true,
- RestrictedUntilDate: c.formatBantime(hours),
- Permissions: &permissionsReadonly,
- },
- })
- if err != nil {
- return err.Error(), true, false
+ var hours int64
+ if len(args) > 1 {
+ hours, err = strconv.ParseInt(args[1], 10, 32)
+ if err != nil {
+ return "Invalid number of hours", true, false
+ }
+ }
+
+ _, err = c.client.SetChatMemberStatus(&client.SetChatMemberStatusRequest{
+ ChatId: chatID,
+ MemberId: &client.MessageSenderUser{UserId: contact.Id},
+ Status: &client.ChatMemberStatusRestricted{
+ IsMember: true,
+ RestrictedUntilDate: c.formatBantime(hours),
+ Permissions: &permissionsReadonly,
+ },
+ })
+ if err != nil {
+ return err.Error(), true, false
+ }
+ } else {
+ if !c.Session.IgnoreChat(chatID) {
+ return "Chat is already ignored", true, false
+ }
+ gateway.DirtySessions = true
}
- // unmute @username
+ // unmute [@username]
case "unmute":
- contact, _, err := c.GetContactByUsername(args[0])
- if err != nil {
- return err.Error(), true, false
- }
- if contact == nil {
- return "Contact not found", true, false
- }
+ if len(args) > 0 {
+ contact, _, err := c.GetContactByUsername(args[0])
+ if err != nil {
+ return err.Error(), true, false
+ }
+ if contact == nil {
+ return "Contact not found", true, false
+ }
- _, err = c.client.SetChatMemberStatus(&client.SetChatMemberStatusRequest{
- ChatId: chatID,
- MemberId: &client.MessageSenderUser{UserId: contact.Id},
- Status: &client.ChatMemberStatusRestricted{
- IsMember: true,
- RestrictedUntilDate: 0,
- Permissions: &permissionsMember,
- },
- })
- if err != nil {
- return err.Error(), true, false
+ _, err = c.client.SetChatMemberStatus(&client.SetChatMemberStatusRequest{
+ ChatId: chatID,
+ MemberId: &client.MessageSenderUser{UserId: contact.Id},
+ Status: &client.ChatMemberStatusRestricted{
+ IsMember: true,
+ RestrictedUntilDate: 0,
+ Permissions: &permissionsMember,
+ },
+ })
+ if err != nil {
+ return err.Error(), true, false
+ }
+ } else {
+ if !c.Session.UnignoreChat(chatID) {
+ return "Chat wasn't ignored", true, false
+ }
+ gateway.DirtySessions = true
}
// ban @username from current chat [for N hours]
case "ban":
diff --git a/telegram/handlers.go b/telegram/handlers.go
index 6266292..1ccd622 100644
--- a/telegram/handlers.go
+++ b/telegram/handlers.go
@@ -235,6 +235,9 @@ func (c *Client) updateChatLastMessage(update *client.UpdateChatLastMessage) {
// message received
func (c *Client) updateNewMessage(update *client.UpdateNewMessage) {
chatId := update.Message.ChatId
+ if c.Session.IsChatIgnored(chatId) {
+ return
+ }
// guarantee sequential message delivering per chat
lock := c.getChatMessageLock(chatId)
@@ -261,6 +264,10 @@ func (c *Client) updateNewMessage(update *client.UpdateNewMessage) {
// message content updated
func (c *Client) updateMessageContent(update *client.UpdateMessageContent) {
+ if c.Session.IsChatIgnored(update.ChatId) {
+ return
+ }
+
markupFunction := c.getFormatter()
defer c.updateLastMessageHash(update.ChatId, update.MessageId, update.NewContent)
@@ -353,6 +360,10 @@ func (c *Client) updateMessageContent(update *client.UpdateMessageContent) {
// message(s) deleted
func (c *Client) updateDeleteMessages(update *client.UpdateDeleteMessages) {
if update.IsPermanent {
+ if c.Session.IsChatIgnored(update.ChatId) {
+ return
+ }
+
var deleteChar string
if c.Session.AsciiArrows {
deleteChar = "X "