invites: emails -> messages, log when sendTo attempted when disabled

A user's lengthy debugging resulted in them figuring out "Invite
emails" being disabled stopped the "/inv" command from sending invites
on discord, which makes sense except the confusing setting name (now
renamed "Messages" in the UI), and the fact that no error was reported.
This setting being disabled is now logged to the console when it's
attempted through the admin page or discord. For #378.
This commit is contained in:
Harvey Tindall
2025-07-14 13:58:03 +01:00
parent 4f02c44e39
commit 41ddf73e4f
4 changed files with 90 additions and 85 deletions

View File

@@ -1,6 +1,7 @@
package main
import (
"errors"
"fmt"
"strconv"
"strings"
@@ -195,43 +196,47 @@ func (app *appContext) GenerateInvite(gc *gin.Context) {
invite.UserMinutes = req.UserMinutes
}
invite.ValidTill = validTill
if req.SendTo != "" && app.config.Section("invite_emails").Key("enabled").MustBool(false) {
addressValid := false
discord := ""
if discordEnabled && (!strings.Contains(req.SendTo, "@") || strings.HasPrefix(req.SendTo, "@")) {
users := app.discord.GetUsers(req.SendTo)
if len(users) == 0 {
invite.SendTo = fmt.Sprintf(lm.FailedSendToTooltipNoUser, req.SendTo)
} else if len(users) > 1 {
invite.SendTo = fmt.Sprintf(lm.FailedSendToTooltipMultiUser, req.SendTo)
} else {
invite.SendTo = req.SendTo
addressValid = true
discord = users[0].User.ID
}
} else if emailEnabled {
addressValid = true
invite.SendTo = req.SendTo
}
if addressValid {
msg, err := app.email.constructInvite(invite.Code, invite, app, false)
if err != nil {
// Slight misuse of the template
invite.SendTo = fmt.Sprintf(lm.FailedConstructInviteMessage, req.SendTo, err)
app.err.Printf(lm.FailedConstructInviteMessage, invite.Code, err)
} else {
var err error
if discord != "" {
err = app.discord.SendDM(msg, discord)
if req.SendTo != "" {
if !(app.config.Section("invite_emails").Key("enabled").MustBool(false)) {
app.err.Printf(lm.FailedSendInviteMessage, invite.Code, req.SendTo, errors.New(lm.InviteMessagesDisabled))
} else {
addressValid := false
discord := ""
if discordEnabled && (!strings.Contains(req.SendTo, "@") || strings.HasPrefix(req.SendTo, "@")) {
users := app.discord.GetUsers(req.SendTo)
if len(users) == 0 {
invite.SendTo = fmt.Sprintf(lm.FailedSendToTooltipNoUser, req.SendTo)
} else if len(users) > 1 {
invite.SendTo = fmt.Sprintf(lm.FailedSendToTooltipMultiUser, req.SendTo)
} else {
err = app.email.send(msg, req.SendTo)
invite.SendTo = req.SendTo
addressValid = true
discord = users[0].User.ID
}
} else if emailEnabled {
addressValid = true
invite.SendTo = req.SendTo
}
if addressValid {
msg, err := app.email.constructInvite(invite.Code, invite, app, false)
if err != nil {
invite.SendTo = fmt.Sprintf(lm.FailedSendInviteMessage, invite.Code, req.SendTo, err)
app.err.Println(invite.SendTo)
// Slight misuse of the template
invite.SendTo = fmt.Sprintf(lm.FailedConstructInviteMessage, req.SendTo, err)
app.err.Printf(lm.FailedConstructInviteMessage, invite.Code, err)
} else {
app.info.Printf(lm.SentInviteMessage, invite.Code, req.SendTo)
var err error
if discord != "" {
err = app.discord.SendDM(msg, discord)
} else {
err = app.email.send(msg, req.SendTo)
}
if err != nil {
invite.SendTo = fmt.Sprintf(lm.FailedSendInviteMessage, invite.Code, req.SendTo, err)
app.err.Println(invite.SendTo)
} else {
app.info.Printf(lm.SentInviteMessage, invite.Code, req.SendTo)
}
}
}
}

View File

@@ -1138,7 +1138,7 @@ sections:
type: note
depends_true: link_reset
required: false
description: Set the "External jfa-go URL" in General so that links to jfa-go can be made.
description: Set the "External jfa-go URL" value in General so that links to jfa-go can be made.
- setting: language
name: Default reset link language
requires_restart: true
@@ -1167,9 +1167,9 @@ sections:
description: Subject of password reset emails.
- section: invite_emails
meta:
name: Invite emails
name: Invite Messages
description: Settings for sending invites directly to users.
depends_true: email|method
depends_true: messages|enabled
settings:
- setting: enabled
name: Enabled

View File

@@ -1,6 +1,7 @@
package main
import (
"errors"
"fmt"
"net/http"
"strings"
@@ -605,6 +606,21 @@ func (d *DiscordDaemon) cmdInvite(s *dg.Session, i *dg.InteractionCreate, lang s
requester := d.MustGetUser(channel.ID, i.Interaction.Member.User.ID, i.Interaction.Member.User.Discriminator, i.Interaction.Member.User.Username)
d.users[i.Interaction.Member.User.ID] = requester
recipient := i.ApplicationCommandData().Options[0].UserValue(s)
// We don't reveal much in the message response itself so we can re-use this easily.
sendResponse := func(langKey string) {
err := s.InteractionRespond(i.Interaction, &dg.InteractionResponse{
Type: dg.InteractionResponseChannelMessageWithSource,
Data: &dg.InteractionResponseData{
Content: d.app.storage.lang.Telegram[lang].Strings.get(langKey),
Flags: 64, // Ephemeral
},
})
if err != nil {
d.app.err.Printf(lm.FailedReply, lm.Discord, requester.ID, err)
}
}
// d.app.debug.Println(invuser)
//label := i.ApplicationCommandData().Options[2].StringValue()
//profile := i.ApplicationCommandData().Options[3].StringValue()
@@ -615,13 +631,7 @@ func (d *DiscordDaemon) cmdInvite(s *dg.Session, i *dg.InteractionCreate, lang s
// We want the same criteria for running this command as accessing the admin page (i.e. an "admin" of some sort)
if !(d.app.canAccessAdminPageByID(requester.JellyfinID)) {
d.app.err.Printf(lm.FailedGenerateInvite, fmt.Sprintf(lm.NonAdminUser, requester.JellyfinID))
s.InteractionRespond(i.Interaction, &dg.InteractionResponse{
Type: dg.InteractionResponseChannelMessageWithSource,
Data: &dg.InteractionResponseData{
Content: d.app.storage.lang.Telegram[lang].Strings.get("noPermission"),
Flags: 64, // Ephemeral
},
})
sendResponse("noPermission")
return
}
@@ -663,54 +673,43 @@ func (d *DiscordDaemon) cmdInvite(s *dg.Session, i *dg.InteractionCreate, lang s
}
}
if recipient != nil && d.app.config.Section("invite_emails").Key("enabled").MustBool(false) {
invname, err := d.bot.GuildMember(d.guildID, recipient.ID)
if recipient != nil {
err = nil
var invname *dg.Member = nil
invname, err = d.bot.GuildMember(d.guildID, recipient.ID)
invite.SendTo = invname.User.Username
msg, err := d.app.email.constructInvite(invite.Code, invite, d.app, false)
if err != nil {
invite.SendTo = fmt.Sprintf(lm.FailedConstructInviteMessage, invite.Code, err)
d.app.err.Println(invite.SendTo)
err := s.InteractionRespond(i.Interaction, &dg.InteractionResponse{
Type: dg.InteractionResponseChannelMessageWithSource,
Data: &dg.InteractionResponseData{
Content: d.app.storage.lang.Telegram[lang].Strings.get("sentInviteFailure"),
Flags: 64, // Ephemeral
},
})
if err == nil && !(d.app.config.Section("invite_emails").Key("enabled").MustBool(false)) {
err = errors.New(lm.InviteMessagesDisabled)
}
var msg *Message
if err == nil {
msg, err = d.app.email.constructInvite(invite.Code, invite, d.app, false)
if err != nil {
d.app.err.Printf(lm.FailedReply, lm.Discord, requester.ID, err)
}
} else {
var err error
err = d.app.discord.SendDM(msg, recipient.ID)
if err != nil {
invite.SendTo = fmt.Sprintf(lm.FailedSendInviteMessage, invite.Code, RenderDiscordUsername(recipient), err)
// Print extra message, ideally we'd just print this, or get rid of it though.
invite.SendTo = fmt.Sprintf(lm.FailedConstructInviteMessage, invite.Code, err)
d.app.err.Println(invite.SendTo)
err := s.InteractionRespond(i.Interaction, &dg.InteractionResponse{
Type: dg.InteractionResponseChannelMessageWithSource,
Data: &dg.InteractionResponseData{
Content: d.app.storage.lang.Telegram[lang].Strings.get("sentInviteFailure"),
Flags: 64, // Ephemeral
},
})
if err != nil {
d.app.err.Printf(lm.FailedReply, lm.Discord, requester.ID, err)
}
} else {
d.app.info.Printf(lm.SentInviteMessage, invite.Code, RenderDiscordUsername(recipient))
err := s.InteractionRespond(i.Interaction, &dg.InteractionResponse{
Type: dg.InteractionResponseChannelMessageWithSource,
Data: &dg.InteractionResponseData{
Content: d.app.storage.lang.Telegram[lang].Strings.get("sentInvite"),
Flags: 64, // Ephemeral
},
})
if err != nil {
d.app.err.Printf(lm.FailedReply, lm.Discord, requester.ID, err)
}
}
}
if err == nil {
err = d.app.discord.SendDM(msg, recipient.ID)
}
if err == nil {
d.app.info.Printf(lm.SentInviteMessage, invite.Code, RenderDiscordUsername(recipient))
sendResponse("sentInvite")
}
if err != nil {
invite.SendTo = fmt.Sprintf(lm.FailedSendInviteMessage, invite.Code, RenderDiscordUsername(recipient), err)
d.app.err.Println(invite.SendTo)
sendResponse("sentInviteFailure")
}
}
//if profile != "" {
d.app.storage.SetInvitesKey(invite.Code, invite)
}

View File

@@ -355,6 +355,7 @@ const (
FailedConstructInviteMessage = "Failed to construct invite message for \"%s\": %v"
FailedSendInviteMessage = "Failed to send invite message for \"%s\" to \"%s\": %v"
SentInviteMessage = "Sent invite message for \"%s\" to \"%s\""
InviteMessagesDisabled = "invite messages are disabled, check settings"
FailedConstructConfirmationEmail = "Failed to construct confirmation email for \"%s\": %v"
FailedSendConfirmationEmail = "Failed to send confirmation email for \"%s\" to \"%s\": %v"