nmdc-telegramfrontend/linkBotMenu.go

203 lines
6.3 KiB
Go

package main
import (
"fmt"
"log"
"regexp"
"strings"
"code.ivysaur.me/libnmdc"
telegram "github.com/go-telegram-bot-api/telegram-bot-api"
)
// registerUser lodges a user mapping in the configuration file.
// This allows them to join the group chat (unbanning them if necessary).
// An actual NMDC connection will occur once the user joins for the first time.
func (this *NTFServer) registerUser(telegramUserId int64, hubUsername string) error {
if existingHubNick, ok := this.config.KnownUsers[telegramUserId]; ok {
if existingHubNick == hubUsername {
return nil
}
return fmt.Errorf("Telegram account is already registered with hub nick '%s'", existingHubNick)
}
for _, v := range this.config.KnownUsers {
if v == hubUsername {
return fmt.Errorf("Requested hub nick '%s' is already used by another member", hubUsername)
}
}
this.config.KnownUsers[telegramUserId] = hubUsername
err := this.config.Save(this.configFile)
if err != nil {
return err
}
// Unban from groupchat, if necessary
// Ignore errors because the user might not have been banned
_, err = this.bot.UnbanChatMember(telegram.ChatMemberConfig{
ChatID: this.config.GroupChatID,
UserID: int(telegramUserId),
})
if err != nil {
log.Printf("Couldn't unban user '%s' from groupchat because: %s (assuming OK, continuing)", hubUsername, err.Error())
}
return nil
}
func (this *NTFServer) HandleDirectMessage(update telegram.Update) error {
// Registration workflow
userID := int64(update.Message.From.ID)
// Stash the telegram user ID against this direct-message chat ID so that
// we can always reply later on
chatID := update.Message.Chat.ID
if oldChatID, ok := this.config.DirectMessageChats[userID]; !ok || oldChatID != chatID {
this.config.DirectMessageChats[userID] = chatID
err := this.config.Save(this.configFile)
if err != nil {
log.Printf("Couldn't save chat ID %d for user %d", chatID, userID)
}
}
respond := func(str string) error {
return this.ReplyTelegramUser(userID, str, update.Message.MessageID)
}
// Find out the current status for this chat ID
hubNick, isKnown := this.config.KnownUsers[userID]
_, isInGroupChat := this.config.GroupChatMembers[userID]
// Handle the incoming request
msg := update.Message.Text
if strings.HasPrefix(msg, "/pm ") {
if !(isKnown && isInGroupChat) {
return respond("Can't send a native PM until you've joined.")
}
conn, ok := this.conns[hubNick]
if !ok {
return respond("Can't send a native PM (No upstream hub connection)")
}
parts := strings.SplitN(msg, " ", 3)
if len(parts) != 3 {
return respond("Expected format /pm [recipient] [message] - try again...")
}
if !conn.UserExists(parts[1]) {
return respond(fmt.Sprintf("Can't PM offline user '%s'", parts[1]))
}
err := conn.SayPrivate(parts[1], parts[2])
if err != nil {
log.Printf("Sending PM %s -> %s failed because: %s", hubNick, parts[1], err.Error())
return respond(fmt.Sprintf("Sending PM failed because: %s", err.Error()))
}
} else if strings.HasPrefix(msg, "/join ") {
requestedHubNick := msg[6:]
// Some users take the [] in the message literally. A-Za-z0-9 are the only supported characters
requestedHubNick = regexp.MustCompile(`[^a-zA-Z0-9]`).ReplaceAllString(requestedHubNick, "")
// Minimum nick lengths
if len(requestedHubNick) < this.config.HubNickMinChars {
return respond(fmt.Sprintf("Upstream nickname '%s' should be at least %d characters long", requestedHubNick, this.config.HubNickMinChars))
}
err := this.registerUser(userID, requestedHubNick)
if err != nil {
log.Printf("Failed to register user: %s", err.Error())
return respond(fmt.Sprintf("Couldn't allow registration because: %s", err.Error()))
}
return respond(fmt.Sprintf("Hi '%s'! You are now registered, and can join %s at %s", requestedHubNick, this.config.HubDescription, this.inviteLink))
} else if strings.HasPrefix(msg, "/rejoin") {
if isKnown && !isInGroupChat {
return respond(fmt.Sprintf("Welcome back '%s'! You can join %s at %s", hubNick, this.config.HubDescription, this.inviteLink))
} else {
return respond("You are either already joined (try /quit first), or not yet registered (try /join first).")
}
} else if strings.HasPrefix(msg, "/userlist") {
conn, ok := this.conns[hubNick]
if !ok {
return respond("Can't get userlist for you (No upstream hub connection)")
}
usernames, err := this.getUserlistText(conn)
if err != nil {
return respond("Can't get userlist for you (internal error)")
}
return respond("Online users: " + usernames)
} else if strings.HasPrefix(msg, "/whois ") {
target := msg[7:]
conn, ok := this.conns[hubNick]
if !ok {
return respond("Can't get user details for you (No upstream hub connection)")
}
var userinfo libnmdc.UserInfo
var exists bool
err := conn.Users(func(umap *map[string]libnmdc.UserInfo) error {
userinfo, exists = (*umap)[target]
return nil
})
if err != nil {
log.Printf("Error retrieving userlist: %s", err.Error())
return respond("Can't get user details for you (internal error)")
}
if !exists {
return respond(fmt.Sprintf("There is no online user '%s'.", target))
}
return respond(fmt.Sprintf("Description: %s\nShare size: %d\nClient: %s %s", userinfo.Description, userinfo.ShareSize, userinfo.ClientTag, userinfo.ClientVersion))
} else if strings.HasPrefix(msg, "/quit") {
this.kickAndDrop(userID)
return respond("Disconnected. You can register again by typing /help .")
} else { // e.g. /start or /help
// Help
helpMsg := `I am a bot that connects Telegram with ` + this.config.HubDescription + ".\n"
if isKnown {
helpMsg += "You are currently registered as: '" + hubNick + "'\n"
} else {
helpMsg += "You aren't connected yet.\n"
}
if isInGroupChat {
helpMsg += "You are currently in the groupchat.\n"
} else {
helpMsg += "You haven't joined the groupchat.\n"
}
helpMsg += `
Available commands:
/setup - Welcome message
/join [hubnick] - Register as 'hubnick' and join ` + this.config.HubDescription + `
/rejoin - Re-invite if you are already registered
/pm [recipient] [message] - Send a native PM (if connected)
/userlist - List native online users
/whois [hubnick] - Check if native user is online, and read their description
/quit - Unregister your nick and leave the group chat
`
return respond(helpMsg)
}
return nil
}