diff --git a/gateway/command.go b/gateway/command.go index 03698726b7..e68fe4d169 100644 --- a/gateway/command.go +++ b/gateway/command.go @@ -6,33 +6,47 @@ import ( "github.com/42wim/matterbridge/bridge/config" ) +func (r *Router) handleHelp(msg *config.Message) { + help := `*!help* - display this message +*!optout* - opt out from all message relaying +*!optoutmedia* - only opt out from relaying attachments +*!optin* - opt back into chat relaying +*!setname {NewName}* - use "NewName" as a nickname +*!unsetname* - clear custom name on the bridge +*!setavatar {imageURL}* - use "imageURL" as a custom avatar (will only show up on discord - must be a public image url) +*!unsetavatar* - clear custom avatar on the bridge +*!showstatus* - show your current user preferences` + + isAdmin := r.isAdmin(msg) + + if msg.Channel != msg.UserID { + help = "Note that commands can be run from any chat - *including DM'ing the bot.*\n\n" + help + } + if isAdmin { + help += ` + +*Admin Commands:* +*!setwelcome {WelcomeMsg}* - set channel welcome message (supports attachments) +*!unsetwelcome* - clear channel welcome message` + } + + if msg.Protocol != "whatsapp" && msg.Protocol != "discord" { + help = strings.ReplaceAll(help, "*", "") + } + + r.replyCmd(msg, help) +} + // returns true if a command was registered (therefore a should not be relayed func (r *Router) handleCommand(msg *config.Message) bool { - help := `!optout - opt out from all message relaying - !optoutmedia - only opt out from relaying attachments - !optin - opt back into chat relaying - !setwelcome - set channel welcome message (admin) - !unsetwelcome - clear channel welcome message (admin) - !help - display this message` - isAdmin := r.isAdmin(msg) - addTextFromCaptions(msg) + addTextFromCaptions(msg) // todo: figure out if this would cause a bug cmd := msg.Text switch { case cmd == "!help": r.logger.Debug("!help") - r.replyCmd(msg, help) - case cmd == "!chatId": - r.logger.Infof("!chatId: %s", msg.Channel) - case cmd == "!userId": - r.logger.Infof("!userId: %s", msg.UserID) - case cmd == "!ping": - r.logger.Debug("!pong: %s,%s", msg.Channel, msg.UserID) - r.replyCmd(msg, "pong!") - case cmd == "!pingdm": - r.logger.Debug("!pongdm: %s,%s", msg.Channel, msg.UserID) - r.replyDM(msg, "pong!") + r.handleHelp(msg) case cmd == "!optin": r.logger.Debugf("!optin: %s", msg.UserID) r.handleOptOutCmd(msg, OptIn) @@ -42,12 +56,39 @@ func (r *Router) handleCommand(msg *config.Message) bool { case cmd == "!optoutmedia": r.logger.Debugf("!optoutmedia: %s", msg.UserID) r.handleOptOutCmd(msg, OptOutMediaOnly) + case strings.HasPrefix(cmd, "!setname"): + r.logger.Debugf("%s - %s", cmd, msg.UserID) + r.handleNameCmd(msg, cmd) + case cmd == "!unsetname": + r.logger.Debugf("!unsetname: %s", msg.UserID) + r.handleNameCmd(msg, "!setname ") // bit of a hack lol + case strings.HasPrefix(cmd, "!setavatar"): + r.logger.Debugf("%s - %s", cmd, msg.UserID) + r.handleAvatarCmd(msg, cmd) + case cmd == "!unsetavatar": + r.logger.Debugf("!unsetname: %s", msg.UserID) + r.handleAvatarCmd(msg, "!setavatar ") // bit of a hack lol + case cmd == "!showstatus": + r.logger.Debugf("!showstatus: %s", msg.UserID) + r.handleStatusCmd(msg) + // ! ------- admin commands ------- case isAdmin && strings.HasPrefix(cmd, "!setwelcome"): r.logger.Debugf("!setwelcome: %s - %+v", msg.Channel, msg) r.handleWelcomeCmd(msg, msg) case isAdmin && strings.HasPrefix(cmd, "!unsetwelcome"): r.logger.Debugf("!unsetwelcome: %s", msg.Channel) r.handleWelcomeCmd(msg, nil) + // ! ------- debug commands ------- + case cmd == "!chatId": + r.logger.Infof("!chatId: %s", msg.Channel) + case cmd == "!userId": + r.logger.Infof("!userId: %s", msg.UserID) + case cmd == "!ping": + r.logger.Debug("!pong: %s,%s", msg.Channel, msg.UserID) + r.replyCmd(msg, "pong!") + case cmd == "!pingdm": + r.logger.Debug("!pongdm: %s,%s", msg.Channel, msg.UserID) + r.replyDM(msg, "pong!") case cmd == "!echowelcome": r.logger.Debugf("!echowelcome: %s,%s", msg.Channel, msg.UserID) r.handleEchoWelcomeCmd(msg) @@ -133,6 +174,40 @@ func (r *Router) handleOptOutCmd(msg *config.Message, newStatus OptOutStatus) { r.replyCmd(msg, reply) } +func (r *Router) handleNameCmd(msg *config.Message, cmd string) { + + newName := strings.Replace(cmd, "!setname ", "", 1) + + err := r.setUserName(msg.UserID, newName) + + reply := "Successfully set new name: " + r.getUserName(msg) + if err != nil { + reply = "Error setting nickname, try again later or contact the moderators." + } + + r.replyCmd(msg, reply) +} + +func (r *Router) handleAvatarCmd(msg *config.Message, cmd string) { + + newAvatar := strings.Replace(cmd, "!setavatar ", "", 1) + + err := r.setAvatar(msg.UserID, newAvatar) + + reply := "Successfully set new avatar: " + r.getAvatar(msg) + if err != nil { + reply = "Error setting avatar, try again later or contact the moderators." + } + + r.replyCmd(msg, reply) +} + +func (r *Router) handleStatusCmd(msg *config.Message) { + + reply := r.getUserPreferencesStr(msg) + r.replyCmd(msg, reply) +} + func (r *Router) handleWelcomeCmd(msg *config.Message, welcomeMsg *config.Message) { if welcomeMsg != nil { @@ -163,7 +238,7 @@ func (r *Router) handleEchoWelcomeCmd(msg *config.Message) { msg.Event = config.EventWelcomeMsg srcBridge := r.getBridge(msg.Account) - str := srcBridge.Channels[msg.Channel+msg.Account].Options.WelcomeMessage + str := srcBridge.Channels[getChannelID(msg)].Options.WelcomeMessage if r.getWelcomeMessage(msg.Channel) == nil && str == "" { r.replyCmd(msg, "No welcome message configured, set with !setwelcome") diff --git a/gateway/handlers.go b/gateway/handlers.go index d595df8877..688304d48c 100644 --- a/gateway/handlers.go +++ b/gateway/handlers.go @@ -54,20 +54,25 @@ func (r *Router) handleEventWelcome(msg *config.Message) bool { return false } welcomeMsg := r.getWelcomeMessage(msg.Channel) - srcBridge := r.getBridge(msg.Account) + srcBridge := r.getBridge(msg.Account) str := srcBridge.Channels[msg.Channel+msg.Account].Options.WelcomeMessage - if welcomeMsg != nil { - r.sendDM(welcomeMsg, msg.UserID) - } else if str != "" { + // fallback str from config + if welcomeMsg == nil && str != "" { rmsg := config.Message{ Account: msg.Account, Protocol: msg.Protocol, Event: msg.Event, Text: str, } - r.sendDM(&rmsg, msg.UserID) + + welcomeMsg = &rmsg + } + + if welcomeMsg != nil { + welcomeMsg.Text = strings.ReplaceAll(welcomeMsg.Text, "{NICK}", msg.Username) + r.sendDM(welcomeMsg, msg.UserID) } return true @@ -311,6 +316,21 @@ func (r *Router) handleOptOutUser(msg *config.Message) { } } +func (r *Router) handleName(msg *config.Message) { + msg.Username = r.getUserName(msg) +} + +func (r *Router) handleAvatar(msg *config.Message) { + avatar := r.getAvatar(msg) + + if avatar == "" { + srcBridge := r.getBridge(msg.Account) + avatar = srcBridge.GetString("DefaultAvatar") + } + + msg.Avatar = avatar +} + // extractNick searches for a username (based on "search" a regular expression). // if this matches it extracts a nick (based on "extract" another regular expression) from text // and replaces username with this result. diff --git a/gateway/router.go b/gateway/router.go index b7a80b461a..35c6e43dfe 100644 --- a/gateway/router.go +++ b/gateway/router.go @@ -150,6 +150,8 @@ func (r *Router) handleReceive() { r.handleEventFailure(&msg) r.handleEventRejoinChannels(&msg) r.handleOptOutUser(&msg) + r.handleName(&msg) + r.handleAvatar(&msg) if skipMsg { continue diff --git a/gateway/userstore.go b/gateway/userstore.go index 88c47d33ac..6e206df0cd 100644 --- a/gateway/userstore.go +++ b/gateway/userstore.go @@ -1,6 +1,9 @@ package gateway import ( + "fmt" + + "github.com/42wim/matterbridge/bridge/config" "github.com/philippgille/gokv" "github.com/philippgille/gokv/bbolt" "github.com/philippgille/gokv/encoding" @@ -15,7 +18,9 @@ const ( ) type UserData struct { - OptOut OptOutStatus + OptOut OptOutStatus + UserName string + Avatar string } func (r *Router) getUserStore(path string) gokv.Store { @@ -33,6 +38,23 @@ func (r *Router) getUserStore(path string) gokv.Store { return store } +func (r *Router) getUserPreferencesStr(msg *config.Message) string { + optStr := getOptStr(r.getOptOutStatus(msg.UserID)) + userName := r.getUserName(msg) + avatar := r.getAvatar(msg) + if avatar == "" { + avatar = "None" + } + + status := fmt.Sprintf(`User Preferences: +OptIn Status: %s +UserName: %s +Avatar: %s +`, optStr, userName, avatar) + + return status +} + func (r *Router) getOptOutStatus(UserID string) OptOutStatus { userdata := new(UserData) found, err := r.UserStore.Get(UserID, userdata) @@ -59,3 +81,70 @@ func (r *Router) setOptOutStatus(UserID string, newStatus OptOutStatus) error { } return err } + +func (r *Router) getUserName(msg *config.Message) string { + userdata := new(UserData) + found, err := r.UserStore.Get(msg.UserID, userdata) + if err != nil { + r.logger.Error(err) + } + + if found && userdata.UserName != "" { + return userdata.UserName + } + + return msg.Username +} + +func (r *Router) setUserName(UserID string, newName string) error { + userdata := new(UserData) + r.UserStore.Get(UserID, userdata) + + userdata.UserName = newName + + err := r.UserStore.Set(UserID, userdata) + if err != nil { + r.logger.Errorf(err.Error()) + } + return err +} + +func (r *Router) getAvatar(msg *config.Message) string { + userdata := new(UserData) + found, err := r.UserStore.Get(msg.UserID, userdata) + if err != nil { + r.logger.Error(err) + } + + if found && userdata.Avatar != "" { + return userdata.Avatar + } + + return msg.Avatar +} + +func (r *Router) setAvatar(UserID string, newAvatar string) error { + userdata := new(UserData) + r.UserStore.Get(UserID, userdata) + + userdata.Avatar = newAvatar + + err := r.UserStore.Set(UserID, userdata) + if err != nil { + r.logger.Errorf(err.Error()) + } + return err +} + +func getOptStr(status OptOutStatus) string { + switch status { + case OptIn: + return "Opt In" + case OptOut: + return "Opt Out" + case OptOutMediaOnly: + return "Opt Out - Attachments Only" + } + + return "Unknown" +}