ALFRED/commands/subscribe.go

395 lines
10 KiB
Go

/*
* @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)
}
}
}