/* * @Authors: Amalvy Arthur, Bartuccio Antoine */ // This module uses a property named "subscribed_chats" in the shared Users structure. // It consists of a list of chatID as a string, chatID are separated by ":" (unix PATH style) // This module uses a property named "saved_messages" in the shared Chats structure // It consists of a slice of string package commands import ( "encoding/json" "strconv" "strings" "git.klmp200.net/ALFRED/ALFRED/shared" tb "gopkg.in/tucnak/telebot.v2" ) type userSubscription struct { ChatID int64 AutoNotify bool } // subscriptions are stored in format ChatID(int64),AutoNotify(bool):ChatID,AutoNotify func getUserSubscribedChats(username string) []userSubscription { serializedSubscriptions, exists := shared.Users.Get(username, "subscribed_chats") if !exists { return []userSubscription{} } subscriptions := []userSubscription{} for _, sub := range strings.Split(serializedSubscriptions, ":") { splitedSub := strings.Split(sub, ",") // malformated if len(splitedSub) == 0 { continue } chatID, err := strconv.ParseInt(splitedSub[0], 10, 64) if err != nil { continue } // only ChatID if len(splitedSub) == 1 { subscriptions = append(subscriptions, userSubscription{ ChatID: chatID, AutoNotify: true, }) continue } autoNotify, err := strconv.ParseBool(splitedSub[1]) if err != nil { autoNotify = true } subscriptions = append(subscriptions, userSubscription{ ChatID: chatID, AutoNotify: autoNotify, }) } return subscriptions } func setUserSubscribedChats(username string, subscriptions []userSubscription) { subs := make([]string, len(subscriptions)) for i, sub := range subscriptions { subs[i] = strings.Join( []string{ strconv.FormatInt(sub.ChatID, 10), strconv.FormatBool(sub.AutoNotify), }, ",", ) } shared.Users.Set(username, "subscribed_chats", strings.Join(subs, ":")) } func getPublishedMessages(chatID int64) []tb.Message { messages := []tb.Message{} serializedMessages, exists := shared.ChatData.Get(chatID, "published_messages") if !exists { return messages } if _, ok := serializedMessages.(string); !ok { return messages } if json.Unmarshal([]byte(serializedMessages.(string)), &messages) != nil { return []tb.Message{} } return messages } func setPublishedMessages(chatID int64, messages []tb.Message) { data, err := json.Marshal(messages) if err != nil { return } shared.ChatData.Set(chatID, "published_messages", string(data)) } // Subscribe user sending the command to the current chat // Command syntax : /subscribe func Subscribe(m *tb.Message) { if m.Chat.Type != tb.ChatGroup && m.Chat.Type != tb.ChatSuperGroup { shared.Bot.Send(m.Chat, "Cette commande n'est pas autorisée pour ce type de chat") return } if m.Sender.Username == "" { shared.Bot.Send(m.Chat, "Il faut avoir enregistré un username pour pouvoir utiliser cette fonction") return } subscriptions := getUserSubscribedChats(m.Sender.Username) alreadySuscribed := false for _, sub := range subscriptions { if sub.ChatID == m.Chat.ID { alreadySuscribed = true break } } if alreadySuscribed { shared.Bot.Send(m.Chat, "Vous êtes déjà abonné à ce chat : "+m.Chat.Title) return } shared.Bot.Send(m.Chat, "Abonnement au chat : "+m.Chat.Title) subscriptions = append(subscriptions, userSubscription{ ChatID: m.Chat.ID, AutoNotify: true, }) setUserSubscribedChats(m.Sender.Username, subscriptions) } // Unsubscribe user sending the command from the current chat // Command syntax : /unsubscribe func Unsubscribe(m *tb.Message) { if m.Chat.Type != tb.ChatGroup && m.Chat.Type != tb.ChatSuperGroup { shared.Bot.Send(m.Chat, "Cette commande n'est pas autorisée pour ce type de chat") return } if m.Sender.Username == "" { shared.Bot.Send(m.Chat, "Il faut avoir enregistré un username pour pouvoir utiliser cette fonction") return } subscriptions := getUserSubscribedChats(m.Sender.Username) if len(subscriptions) == 0 { shared.Bot.Send(m.Chat, "Vous n'êtes abonnés à aucun chat") return } filteredSubscriptions := []userSubscription{} wasSuscribed := false for _, sub := range subscriptions { if sub.ChatID == m.Chat.ID { wasSuscribed = true continue } filteredSubscriptions = append(filteredSubscriptions, sub) } if !wasSuscribed { shared.Bot.Send(m.Chat, "Vous n'êtes pas abonné au chat : "+m.Chat.Title) return } shared.Bot.Send(m.Chat, "désabonnement du chat : "+m.Chat.Title) setUserSubscribedChats(m.Sender.Username, filteredSubscriptions) } // ListSubscribers List all subscribers of the current chat // Command syntax : /listsubscribers func ListSubscribers(m *tb.Message) { if m.Chat.Type != tb.ChatGroup && m.Chat.Type != tb.ChatSuperGroup { shared.Bot.Send(m.Chat, "Cette commande n'est pas autorisée pour ce type de chat") return } subscribers := m.Chat.Title + " subscribers : \n\n" for _, subscriber := range getSubscribers(m.Chat.ID) { subscribers = subscribers + "- " + subscriber + "\n" } shared.Bot.Send(m.Chat, subscribers) } // Publish a message from the current chat // Command syntax (while replying to a message) : /publish func Publish(m *tb.Message) { if m.ReplyTo == nil { shared.Bot.Send(m.Chat, "Veuillez répondre à un message pour le publier") return } if m.Chat.Type != tb.ChatGroup && m.Chat.Type != tb.ChatSuperGroup { shared.Bot.Send(m.Chat, "Cette commande n'est pas autorisée pour ce type de chat") return } defer shared.Bot.Send(m.Chat, "Message publié : "+m.ReplyTo.Text) savedMessages := getPublishedMessages(m.Chat.ID) setPublishedMessages(m.Chat.ID, append(savedMessages, *m.ReplyTo)) go pushUpdates(m.Chat.ID, m.ReplyTo) } // Unpublish remove a message from published messages in the current chat // Command syntax (while replying to a message) : /unpublish func Unpublish(m *tb.Message) { if m.Chat.Type != tb.ChatGroup && m.Chat.Type != tb.ChatSuperGroup { shared.Bot.Send(m.Chat, "Cette commande n'est pas autorisée pour ce type de chat") return } if m.ReplyTo == nil { shared.Bot.Send(m.Chat, "Veuillez répondre à un message pour le dépublier") return } if !m.ReplyTo.IsForwarded() { shared.Bot.Send(m.Chat, "Ce message ne peut pas avoir été publié") return } publishedMessages := getPublishedMessages(m.Chat.ID) filteredPublishedMessages := []tb.Message{} found := false for _, message := range publishedMessages { // You can't just compare messages id because // when retrieving, the newly send message // has a different ID from the one stored so you can't detect that's // it's in the database except if you find the original message // which is very unlikely to happen // As a workaround, we check the original sender, original unix time // and associated text if message.Sender.ID == m.ReplyTo.OriginalSender.ID && message.Unixtime == int64(m.ReplyTo.OriginalUnixtime) && message.Text == m.ReplyTo.Text { found = true continue } filteredPublishedMessages = append(filteredPublishedMessages, message) } if !found { shared.Bot.Send(m.Chat, "Ce message n'a jamais été publié") return } setPublishedMessages(m.Chat.ID, filteredPublishedMessages) shared.Bot.Send(m.Chat, "Message supprimé des publication") } // Retrieve If performed in MP : retrieve all messages from all subscribed sources for the user // If performed in Group Chat : retrieved all published messages for this chat // Command syntax : /retrieve func Retrieve(m *tb.Message) { chatList := []userSubscription{} hasMessage := false if m.Chat.Type != tb.ChatGroup && m.Chat.Type != tb.ChatSuperGroup && m.Chat.Type != tb.ChatPrivate { shared.Bot.Send(m.Chat, "Cette commande n'est pas autorisée pour ce type de chat") return } if m.Chat.Type == tb.ChatPrivate { if m.Sender.Username == "" { shared.Bot.Send(m.Chat, "Il faut avoir enregistré un username pour pouvoir utiliser cette fonction") return } chatList = getUserSubscribedChats(m.Sender.Username) } if m.Chat.Type == tb.ChatGroup || m.Chat.Type == tb.ChatSuperGroup { chatList = append(chatList, userSubscription{ChatID: m.Chat.ID}) } shared.Bot.Send(m.Chat, "--- Messages publiés ---") for _, sub := range chatList { messages := getPublishedMessages(sub.ChatID) if len(messages) > 0 { hasMessage = true } for _, message := range messages { shared.Bot.Forward(m.Chat, &message) } } if !hasMessage { shared.Bot.Send(m.Chat, "Aucun message publié") } shared.Bot.Send(m.Chat, "--- Messages publiés ---") } // ToggleUpdates activate/deactivate automatic updates from the current chat // Command syntax : /toggleupdates func ToggleUpdates(m *tb.Message) { if m.Chat.Type != tb.ChatGroup && m.Chat.Type != tb.ChatSuperGroup { shared.Bot.Send(m.Chat, "Cette commande n'est pas autorisée pour ce type de chat") return } if m.Sender.Username == "" { shared.Bot.Send(m.Chat, "Il faut avoir enregistré un username pour pouvoir utiliser cette fonction") return } wasSuscribed := false subAutoNotify := false subscriptions := getUserSubscribedChats(m.Sender.Username) for i, sub := range subscriptions { if sub.ChatID == m.Chat.ID { sub.AutoNotify = !sub.AutoNotify subAutoNotify = sub.AutoNotify subscriptions[i] = sub wasSuscribed = true break } } if !wasSuscribed { shared.Bot.Send(m.Chat, "Vous n'ête pas abonné au chat : "+m.Chat.Title) return } setUserSubscribedChats(m.Sender.Username, subscriptions) if subAutoNotify { shared.Bot.Send(m.Chat, "Les notifications automatiques sont désormais activées pour ce chat") return } shared.Bot.Send(m.Chat, "Les notifications automatiques sont désormais désactivées pour ce chat") } // Get all users subscribed to the provided channel func getSubscribers(chatID int64) []string { var subscribers []string for _, username := range shared.Users.GetUsernames() { subscriptions := getUserSubscribedChats(username) for _, sub := range subscriptions { if sub.ChatID == chatID { subscribers = append(subscribers, username) break } } } return subscribers } func pushUpdates(chatID int64, message *tb.Message) { for _, username := range shared.Users.GetUsernames() { for _, sub := range getUserSubscribedChats(username) { if sub.ChatID != chatID || !sub.AutoNotify { continue } chat, err := shared.Users.GetUserChat(username) if err != nil { continue } shared.Bot.Forward(chat, message) } } }