Add automatic publish notification #17

Merged
klmp200 merged 5 commits from bro-features into master 2019-01-02 23:03:57 +00:00
5 changed files with 288 additions and 74 deletions

View File

@ -1,8 +1,8 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2018-07-23 15:24:22
* @Last Modified by: klmp200
* @Last Modified time: 2018-11-14 00:33:00
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-02 22:58:03
*/
package main
@ -19,25 +19,28 @@ import (
func main() {
registeredCommands := map[string]func(*tb.Message){
tb.OnText: commands.OnText,
"/hello": commands.Hello,
"/sponge": commands.Sponge,
"/git": commands.Git,
"/framapad": commands.Framapad,
"/setgender": commands.SetGender,
"/gender": commands.Gender,
"/roll": commands.Dice,
"/trump": commands.LastTrumpTweet,
"/trends": commands.TwitterTrends,
"/chaos": commands.TwitterSJW,
"/apero": commands.AperoTime,
"/quote": commands.Quote,
"/subscribe": commands.Subscribe,
"/unsubscribe": commands.Unsubscribe,
"/listsubscribers": commands.ListSubscribers,
"/publish": commands.Publish,
"/unpublish": commands.Unpublish,
"/retrieve": commands.Retrieve,
tb.OnText: commands.OnText,
"/registerprivate": commands.RegisterPrivate,
"/unregisterprivate": commands.UnRegisterPrivate,
"/hello": commands.Hello,
"/sponge": commands.Sponge,
"/git": commands.Git,
"/framapad": commands.Framapad,
"/setgender": commands.SetGender,
"/gender": commands.Gender,
"/roll": commands.Dice,
"/trump": commands.LastTrumpTweet,
"/trends": commands.TwitterTrends,
"/chaos": commands.TwitterSJW,
"/apero": commands.AperoTime,
"/quote": commands.Quote,
"/subscribe": commands.Subscribe,
"/unsubscribe": commands.Unsubscribe,
"/listsubscribers": commands.ListSubscribers,
"/publish": commands.Publish,
"/unpublish": commands.Unpublish,
"/retrieve": commands.Retrieve,
"/toggleupdates": commands.ToggleUpdates,
}
if err := settings.LoadSettings("settings.json", "settings_custom.json"); err != nil {

View File

@ -0,0 +1,43 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2019-01-02 22:46:05
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-03 00:02:48
*/
package commands
import (
"../shared"
tb "gopkg.in/tucnak/telebot.v2"
)
// RegisterPrivate registers an user private chat
func RegisterPrivate(m *tb.Message) {
if m.Chat.Type != tb.ChatPrivate {
shared.Bot.Send(m.Chat, "Cette commande n'est disponible qu'en messages privés")
}
if m.Sender.Username == "" {
shared.Bot.Send(m.Chat, "Vous devez avoir enregistré un username")
}
shared.Users.SetUserChat(m.Sender.Username, m.Chat)
shared.Bot.Send(m.Chat, "Votre chat privé a bien été enregistré")
}
// UnRegisterPrivate delete an user private chat
func UnRegisterPrivate(m *tb.Message) {
if m.Chat.Type != tb.ChatPrivate {
shared.Bot.Send(m.Chat, "Cette commande n'est disponible qu'en messages privés")
}
if m.Sender.Username == "" {
shared.Bot.Send(m.Chat, "Vous devez avoir enregistré un username")
}
shared.Users.SetUserChat(m.Sender.Username, nil)
shared.Bot.Send(m.Chat, "Votre chat privé a bien été supprimé")
}

View File

@ -19,6 +19,72 @@ import (
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{}
@ -50,6 +116,7 @@ func setPublishedMessages(chatID int64, messages []tb.Message) {
// Subscribe user sending the command to the current chat
// Command syntax : /subscribe
func Subscribe(m *tb.Message) {
Review

Why an entry?!

:P

Why an entry?! :P
Review

For lisibility :)

For lisibility :)
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
@ -60,30 +127,34 @@ func Subscribe(m *tb.Message) {
return
}
userSubscribedChats, exists := shared.Users.Get(m.Sender.Username, "subscribed_chats")
if !exists {
shared.Bot.Send(m.Chat, "Abonnement au chat : "+m.Chat.Title)
shared.Users.Set(m.Sender.Username, "subscribed_chats", strconv.FormatInt(m.Chat.ID, 10))
return
}
splittedChats := strings.Split(userSubscribedChats, ":")
for _, chatID := range splittedChats {
if chatID == strconv.FormatInt(m.Chat.ID, 10) {
shared.Bot.Send(m.Chat, "Vous êtes déjà abonné à ce chat : "+m.Chat.Title)
return
subscriptions := getUserSubscribedChats(m.Sender.Username)
alreadySuscribed := false
for _, sub := range subscriptions {
if sub.ChatID == m.Chat.ID {
alreadySuscribed = true
break
}
}
shared.Bot.Send(m.Chat, "Abonnement au chat : "+m.Chat.Title)
if len(userSubscribedChats) != 0 {
shared.Users.Set(m.Sender.Username, "subscribed_chats", userSubscribedChats+":"+strconv.FormatInt(m.Chat.ID, 10))
} else {
shared.Users.Set(m.Sender.Username, "subscribed_chats", strconv.FormatInt(m.Chat.ID, 10))
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
@ -94,20 +165,32 @@ func Unsubscribe(m *tb.Message) {
return
}
userSubscribedChats, exists := shared.Users.Get(m.Sender.Username, "subscribed_chats")
if !exists || len(userSubscribedChats) == 0 {
shared.Bot.Send(m.Chat, "Vous n'êtes abonné à aucun chat")
subscriptions := getUserSubscribedChats(m.Sender.Username)
if len(subscriptions) == 0 {
shared.Bot.Send(m.Chat, "Vous n'êtes abonnés à aucun chat")
Review

-s if you're talking to the user :)

-s if you're talking to the user :)
Review

👍

:+1:
return
}
splittedChats := strings.Split(userSubscribedChats, ":")
for i, chatID := range splittedChats {
if chatID == strconv.FormatInt(m.Chat.ID, 10) {
shared.Bot.Send(m.Chat, "désabonnement du chat : "+m.Chat.Title)
splittedChats = append(splittedChats[:i], splittedChats[i+1:]...)
break
filteredSubscriptions := []userSubscription{}
wasSuscribed := false
for _, sub := range subscriptions {
if sub.ChatID == m.Chat.ID {
wasSuscribed = true
continue
}
filteredSubscriptions = append(filteredSubscriptions, sub)
}
shared.Users.Set(m.Sender.Username, "subscribed_chats", strings.Join(splittedChats, ":"))
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
@ -140,6 +223,7 @@ func Publish(m *tb.Message) {
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)
}
@ -195,7 +279,7 @@ func Unpublish(m *tb.Message) {
// If performed in Group Chat : retrieved all published messages for this chat
// Command syntax : /retrieve
func Retrieve(m *tb.Message) {
chatList := []int64{}
chatList := []userSubscription{}
hasMessage := false
if m.Chat.Type != tb.ChatGroup && m.Chat.Type != tb.ChatSuperGroup && m.Chat.Type != tb.ChatPrivate {
@ -204,30 +288,23 @@ func Retrieve(m *tb.Message) {
}
if m.Chat.Type == tb.ChatPrivate {
userSubscribedChats, exists := shared.Users.Get(m.Sender.Username, "subscribed_chats")
if !exists || len(userSubscribedChats) == 0 {
shared.Bot.Send(m.Chat, "Aucun abonnements")
if m.Sender.Username == "" {
shared.Bot.Send(m.Chat, "Il faut avoir enregistré un username pour pouvoir utiliser cette fonction")
return
}
for _, chat := range strings.Split(userSubscribedChats, ":") {
chatID, err := strconv.ParseInt(chat, 10, 64)
if err != nil {
shared.Bot.Send(m.Chat, "Erreur lors de la récupération de vos évènements")
return
}
chatList = append(chatList, chatID)
}
chatList = getUserSubscribedChats(m.Sender.Username)
}
if m.Chat.Type == tb.ChatGroup || m.Chat.Type == tb.ChatSuperGroup {
chatList = append(chatList, m.Chat.ID)
chatList = append(chatList, userSubscription{ChatID: m.Chat.ID})
}
shared.Bot.Send(m.Chat, "--- Messages publiés ---")
for _, chatID := range chatList {
messages := getPublishedMessages(chatID)
for _, sub := range chatList {
messages := getPublishedMessages(sub.ChatID)
if len(messages) > 0 {
hasMessage = true
Review

Désolé de ma méconnaissance mais y'a pas un genre de ternaire pour éviter une grosse condition pour ça ?

Désolé de ma méconnaissance mais y'a pas un genre de ternaire pour éviter une grosse condition pour ça ?
Review

Nope, c'est fait exprès dans le design du langage

Nope, c'est fait exprès dans le design du langage
}
@ -243,19 +320,74 @@ func Retrieve(m *tb.Message) {
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() {
userSubscribedChats, exists := shared.Users.Get(username, "subscribed_chats")
if exists {
splittedChats := strings.Split(userSubscribedChats, ":")
for _, splittedChatID := range splittedChats {
if splittedChatID == strconv.FormatInt(chatID, 10) {
subscribers = append(subscribers, username)
}
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)
}
}
}

View File

@ -36,7 +36,7 @@ The publish module intend to be a "multi-pin" feature for chats, allowing users
### Publish
**Description** : Publish a message to Alfred for this group chat and sends this message via MP to every subscriber of the group chat. The message can then be retrieved using the *retrieve* command.
**Description** : Publish a message to Alfred for this group chat and sends this message via MP to every subscriber of the group chat if they have not mutted it. The message can then be retrieved using the *retrieve* command.
**Usage location** : Group chat only
@ -44,8 +44,6 @@ The publish module intend to be a "multi-pin" feature for chats, allowing users
**Command syntax** : /publish
*note* : MP not implemented
### Unpublish
**Description** : Remove a published message from Alfred for this group chat
@ -65,3 +63,12 @@ The publish module intend to be a "multi-pin" feature for chats, allowing users
**Command syntax** : /retrieve
### ToggleUpdates
**Description**: Activate/Deactivate automatic notifications from publish in the group chat where the command is used. By default, this is enabled.
**Usage location** : Group Chat
**Command syntax** : /toggleupdates
*note* : No notification can be send if the user has never done /registerprivate on a private chat with the bot, this is a limitation of the telegram bot API.

View File

@ -1,16 +1,19 @@
/*
* @Author: Bartuccio Antoine
* @Date: 2018-07-24 14:41:03
* @Last Modified by: klmp200
* @Last Modified time: 2018-07-24 17:49:51
* @Last Modified by: Bartuccio Antoine
* @Last Modified time: 2019-01-02 22:37:58
*/
package shared
import (
"encoding/json"
"fmt"
"io/ioutil"
"sync"
tb "gopkg.in/tucnak/telebot.v2"
)
type users struct {
@ -23,6 +26,7 @@ type usersFile struct {
path string
}
// Users shared user for commands
var Users users
var uf usersFile
@ -72,6 +76,31 @@ func (u users) GetUsernames() []string {
return usernames
}
// GetUserChat retrieve the chat of the user if registered
func (u users) GetUserChat(username string) (*tb.Chat, error) {
serializedChat, exists := u.Get(username, "private_chat")
if !exists {
return nil, fmt.Errorf("No private chat registered for %s", username)
}
chat := &tb.Chat{}
if json.Unmarshal([]byte(serializedChat), chat) != nil {
return nil, fmt.Errorf("Error while parsing chat for %s", username)
}
return chat, nil
}
// SetUserChat register a private chat for an user
func (u users) SetUserChat(username string, chat *tb.Chat) {
serializedChat, err := json.Marshal(chat)
if err != nil {
return
}
u.Set(username, "private_chat", string(serializedChat))
}
func (u usersFile) read() {
u.mutex.Lock()
defer u.mutex.Unlock()