mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 09:00:10 +00:00
PIN verification, notifications, multiple notif providers
Discord, Email & Telegram can be enabled, although email is always enabled right now (will fix). Also apparently markdown hyperlinks don't work in Discord, eventually will implement something to convert them to embeds.
This commit is contained in:
parent
524941da0c
commit
f8f5f35cc1
90
api.go
90
api.go
@ -330,6 +330,30 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
||||
success = false
|
||||
return
|
||||
}
|
||||
var discordUser DiscordUser
|
||||
discordVerified := false
|
||||
if discordEnabled {
|
||||
if req.DiscordPIN == "" {
|
||||
if app.config.Section("discord").Key("required").MustBool(false) {
|
||||
f = func(gc *gin.Context) {
|
||||
app.debug.Printf("%s: New user failed: Discord verification not completed", req.Code)
|
||||
respond(401, "errorDiscordVerification", gc)
|
||||
}
|
||||
success = false
|
||||
return
|
||||
}
|
||||
} else {
|
||||
discordUser, discordVerified = app.discord.verifiedTokens[req.DiscordPIN]
|
||||
if !discordVerified {
|
||||
f = func(gc *gin.Context) {
|
||||
app.debug.Printf("%s: New user failed: Discord PIN was invalid", req.Code)
|
||||
respond(401, "errorInvalidPIN", gc)
|
||||
}
|
||||
success = false
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
telegramTokenIndex := -1
|
||||
if telegramEnabled {
|
||||
if req.TelegramPIN == "" {
|
||||
@ -479,7 +503,18 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
||||
app.err.Printf("Failed to store user duration: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if discordEnabled && discordVerified {
|
||||
discordUser.Contact = req.DiscordContact
|
||||
if app.storage.discord == nil {
|
||||
app.storage.discord = map[string]DiscordUser{}
|
||||
}
|
||||
app.storage.discord[user.ID] = discordUser
|
||||
if err := app.storage.storeDiscordUsers(); err != nil {
|
||||
app.err.Printf("Failed to store Discord users: %v", err)
|
||||
} else {
|
||||
delete(app.discord.verifiedTokens, req.DiscordPIN)
|
||||
}
|
||||
}
|
||||
if telegramEnabled && telegramTokenIndex != -1 {
|
||||
tgToken := app.telegram.verifiedTokens[telegramTokenIndex]
|
||||
tgUser := TelegramUser{
|
||||
@ -494,8 +529,7 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
||||
app.storage.telegram = map[string]TelegramUser{}
|
||||
}
|
||||
app.storage.telegram[user.ID] = tgUser
|
||||
err := app.storage.storeTelegramUsers()
|
||||
if err != nil {
|
||||
if err := app.storage.storeTelegramUsers(); err != nil {
|
||||
app.err.Printf("Failed to store Telegram users: %v", err)
|
||||
} else {
|
||||
app.telegram.verifiedTokens[len(app.telegram.verifiedTokens)-1], app.telegram.verifiedTokens[telegramTokenIndex] = app.telegram.verifiedTokens[telegramTokenIndex], app.telegram.verifiedTokens[len(app.telegram.verifiedTokens)-1]
|
||||
@ -503,7 +537,7 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
|
||||
}
|
||||
}
|
||||
|
||||
if (emailEnabled && app.config.Section("welcome_email").Key("enabled").MustBool(false) && req.Email != "") || telegramTokenIndex != -1 {
|
||||
if (emailEnabled && app.config.Section("welcome_email").Key("enabled").MustBool(false) && req.Email != "") || telegramTokenIndex != -1 || discordVerified {
|
||||
name := app.getAddressOrName(user.ID)
|
||||
app.debug.Printf("%s: Sending welcome message to %s", req.Username, name)
|
||||
msg, err := app.email.constructWelcome(req.Username, expiry, app, false)
|
||||
@ -1169,6 +1203,7 @@ func (app *appContext) GetUsers(gc *gin.Context) {
|
||||
}
|
||||
if email, ok := app.storage.emails[jfUser.ID]; ok {
|
||||
user.Email = email.(string)
|
||||
user.NotifyThroughEmail = user.Email != ""
|
||||
}
|
||||
expiry, ok := app.storage.users[jfUser.ID]
|
||||
if ok {
|
||||
@ -1178,6 +1213,11 @@ func (app *appContext) GetUsers(gc *gin.Context) {
|
||||
user.Telegram = tgUser.Username
|
||||
user.NotifyThroughTelegram = tgUser.Contact
|
||||
}
|
||||
if dc, ok := app.storage.discord[jfUser.ID]; ok {
|
||||
user.Discord = dc.Username + "#" + dc.Discriminator
|
||||
user.DiscordID = dc.ID
|
||||
user.NotifyThroughDiscord = dc.Contact
|
||||
}
|
||||
resp.UserList[i] = user
|
||||
i++
|
||||
}
|
||||
@ -2011,7 +2051,7 @@ func (app *appContext) TelegramAddUser(gc *gin.Context) {
|
||||
// @Router /users/telegram/notify [post]
|
||||
// @Security Bearer
|
||||
// @tags Other
|
||||
func (app *appContext) TelegramSetNotify(gc *gin.Context) {
|
||||
func (app *appContext) SetContactMethods(gc *gin.Context) {
|
||||
var req telegramNotifyDTO
|
||||
gc.BindJSON(&req)
|
||||
if req.ID == "" {
|
||||
@ -2019,23 +2059,34 @@ func (app *appContext) TelegramSetNotify(gc *gin.Context) {
|
||||
return
|
||||
}
|
||||
if tgUser, ok := app.storage.telegram[req.ID]; ok {
|
||||
tgUser.Contact = req.Enabled
|
||||
tgUser.Contact = req.Telegram
|
||||
app.storage.telegram[req.ID] = tgUser
|
||||
if err := app.storage.storeTelegramUsers(); err != nil {
|
||||
respondBool(500, false, gc)
|
||||
app.err.Printf("Telegram: Failed to store users: %v", err)
|
||||
return
|
||||
}
|
||||
respondBool(200, true, gc)
|
||||
msg := ""
|
||||
if !req.Enabled {
|
||||
if !req.Telegram {
|
||||
msg = "not"
|
||||
}
|
||||
app.debug.Printf("Telegram: User \"%s\" will %s be notified through Telegram.", tgUser.Username, msg)
|
||||
}
|
||||
if dcUser, ok := app.storage.discord[req.ID]; ok {
|
||||
dcUser.Contact = req.Discord
|
||||
app.storage.discord[req.ID] = dcUser
|
||||
if err := app.storage.storeDiscordUsers(); err != nil {
|
||||
respondBool(500, false, gc)
|
||||
app.err.Printf("Discord: Failed to store users: %v", err)
|
||||
return
|
||||
}
|
||||
app.err.Printf("Telegram: User \"%s\" does not have a telegram account registered.", req.ID)
|
||||
respondBool(400, false, gc)
|
||||
msg := ""
|
||||
if !req.Discord {
|
||||
msg = "not"
|
||||
}
|
||||
app.debug.Printf("Discord: User \"%s\" will %s be notified through Discord.", dcUser.Username, msg)
|
||||
}
|
||||
respondBool(200, true, gc)
|
||||
}
|
||||
|
||||
// @Summary Returns true/false on whether or not a telegram PIN was verified. Requires bearer auth.
|
||||
@ -2092,6 +2143,25 @@ func (app *appContext) TelegramVerifiedInvite(gc *gin.Context) {
|
||||
respondBool(200, tokenIndex != -1, gc)
|
||||
}
|
||||
|
||||
// @Summary Returns true/false on whether or not a discord PIN was verified. Requires invite code.
|
||||
// @Produce json
|
||||
// @Success 200 {object} boolResponse
|
||||
// @Success 401 {object} boolResponse
|
||||
// @Param pin path string true "PIN code to check"
|
||||
// @Param invCode path string true "invite Code"
|
||||
// @Router /invite/{invCode}/discord/verified/{pin} [get]
|
||||
// @tags Other
|
||||
func (app *appContext) DiscordVerifiedInvite(gc *gin.Context) {
|
||||
code := gc.Param("invCode")
|
||||
if _, ok := app.storage.invites[code]; !ok {
|
||||
respondBool(401, false, gc)
|
||||
return
|
||||
}
|
||||
pin := gc.Param("pin")
|
||||
_, ok := app.discord.verifiedTokens[pin]
|
||||
respondBool(200, ok, gc)
|
||||
}
|
||||
|
||||
// @Summary Restarts the program. No response means success.
|
||||
// @Router /restart [post]
|
||||
// @Security Bearer
|
||||
|
@ -588,6 +588,15 @@
|
||||
"value": "!start",
|
||||
"description": "Command to start the user verification process."
|
||||
},
|
||||
"channel": {
|
||||
"name": "Channel to monitor",
|
||||
"required": false,
|
||||
"requires_restart": true,
|
||||
"depens_true": "enabled",
|
||||
"type": "text",
|
||||
"value": "",
|
||||
"description": "Only listen to commands in specified channel. Leave blank to monitor all."
|
||||
},
|
||||
"language": {
|
||||
"name": "Language",
|
||||
"required": false,
|
||||
|
142
discord.go
142
discord.go
@ -7,21 +7,16 @@ import (
|
||||
dg "github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
||||
type DiscordToken struct {
|
||||
Token string
|
||||
ChannelID string
|
||||
UserID string
|
||||
Username string
|
||||
}
|
||||
|
||||
type DiscordDaemon struct {
|
||||
Stopped bool
|
||||
ShutdownChannel chan string
|
||||
bot *dg.Session
|
||||
username string
|
||||
tokens map[string]DiscordToken // map of user IDs to tokens.
|
||||
verifiedTokens []DiscordToken
|
||||
languages map[string]string // Store of languages for user IDs. Added to on first interaction, and loaded from app.storage.discord on start.
|
||||
tokens []string
|
||||
verifiedTokens map[string]DiscordUser // Map of tokens to discord users.
|
||||
channelID, channelName string
|
||||
serverChannelName string
|
||||
users map[string]DiscordUser // Map of user IDs to users. Added to on first interaction, and loaded from app.storage.discord on start.
|
||||
app *appContext
|
||||
}
|
||||
|
||||
@ -38,28 +33,39 @@ func newDiscordDaemon(app *appContext) (*DiscordDaemon, error) {
|
||||
Stopped: false,
|
||||
ShutdownChannel: make(chan string),
|
||||
bot: bot,
|
||||
tokens: map[string]DiscordToken{},
|
||||
verifiedTokens: []DiscordToken{},
|
||||
languages: map[string]string{},
|
||||
tokens: []string{},
|
||||
verifiedTokens: map[string]DiscordUser{},
|
||||
users: map[string]DiscordUser{},
|
||||
app: app,
|
||||
}
|
||||
for _, user := range app.storage.discord {
|
||||
if user.Lang != "" {
|
||||
dd.languages[user.ID] = user.Lang
|
||||
}
|
||||
dd.users[user.ID] = user
|
||||
}
|
||||
return dd, nil
|
||||
}
|
||||
|
||||
func (d *DiscordDaemon) NewAuthToken(channelID, userID, username string) DiscordToken {
|
||||
// NewAuthToken generates an 8-character pin in the form "A1-2B-CD".
|
||||
func (d *DiscordDaemon) NewAuthToken() string {
|
||||
pin := genAuthToken()
|
||||
token := DiscordToken{
|
||||
Token: pin,
|
||||
d.tokens = append(d.tokens, pin)
|
||||
return pin
|
||||
}
|
||||
|
||||
func (d *DiscordDaemon) NewUnknownUser(channelID, userID, discrim, username string) DiscordUser {
|
||||
user := DiscordUser{
|
||||
ChannelID: channelID,
|
||||
UserID: userID,
|
||||
ID: userID,
|
||||
Username: username,
|
||||
Discriminator: discrim,
|
||||
}
|
||||
return token
|
||||
return user
|
||||
}
|
||||
|
||||
func (d *DiscordDaemon) MustGetUser(channelID, userID, discrim, username string) DiscordUser {
|
||||
if user, ok := d.users[userID]; ok {
|
||||
return user
|
||||
}
|
||||
return d.NewUnknownUser(channelID, userID, discrim, username)
|
||||
}
|
||||
|
||||
func (d *DiscordDaemon) run() {
|
||||
@ -70,6 +76,15 @@ func (d *DiscordDaemon) run() {
|
||||
return
|
||||
}
|
||||
d.username = d.bot.State.User.Username
|
||||
// Choose the last guild (server), for now we don't really support multiple anyway
|
||||
guild, err := d.bot.Guild(d.bot.State.Guilds[len(d.bot.State.Guilds)-1].ID)
|
||||
if err != nil {
|
||||
d.app.err.Printf("Discord: Failed to get guild: %v", err)
|
||||
}
|
||||
d.serverChannelName = guild.Name
|
||||
if channel := d.app.config.Section("discord").Key("channel").String(); channel != "" {
|
||||
d.channelName = channel
|
||||
}
|
||||
defer d.bot.Close()
|
||||
<-d.ShutdownChannel
|
||||
d.ShutdownChannel <- "Down"
|
||||
@ -84,6 +99,22 @@ func (d *DiscordDaemon) Shutdown() {
|
||||
}
|
||||
|
||||
func (d *DiscordDaemon) messageHandler(s *dg.Session, m *dg.MessageCreate) {
|
||||
if m.GuildID != "" && d.channelName != "" {
|
||||
if d.channelID == "" {
|
||||
channel, err := s.Channel(m.ChannelID)
|
||||
if err != nil {
|
||||
d.app.err.Printf("Discord: Couldn't get channel, will monitor all: %v", err)
|
||||
d.channelName = ""
|
||||
}
|
||||
if channel.Name == d.channelName {
|
||||
d.channelID = channel.ID
|
||||
}
|
||||
}
|
||||
if d.channelID != m.ChannelID {
|
||||
d.app.debug.Printf("Discord: Ignoring message as not in specified channel")
|
||||
return
|
||||
}
|
||||
}
|
||||
if m.Author.ID == s.State.User.ID {
|
||||
return
|
||||
}
|
||||
@ -92,11 +123,13 @@ func (d *DiscordDaemon) messageHandler(s *dg.Session, m *dg.MessageCreate) {
|
||||
return
|
||||
}
|
||||
lang := d.app.storage.lang.chosenTelegramLang
|
||||
if storedLang, ok := d.languages[m.Author.ID]; ok {
|
||||
lang = storedLang
|
||||
if user, ok := d.users[m.Author.ID]; ok {
|
||||
if _, ok := d.app.storage.lang.Telegram[user.Lang]; ok {
|
||||
lang = user.Lang
|
||||
}
|
||||
}
|
||||
switch msg := sects[0]; msg {
|
||||
case d.app.config.Section("telegram").Key("start_command").MustString("!start"):
|
||||
case d.app.config.Section("discord").Key("start_command").MustString("!start"):
|
||||
d.commandStart(s, m, lang)
|
||||
case "!lang":
|
||||
d.commandLang(s, m, sects, lang)
|
||||
@ -111,8 +144,8 @@ func (d *DiscordDaemon) commandStart(s *dg.Session, m *dg.MessageCreate, lang st
|
||||
d.app.err.Printf("Discord: Failed to create private channel with \"%s\": %v", m.Author.Username, err)
|
||||
return
|
||||
}
|
||||
token := d.NewAuthToken(channel.ID, m.Author.ID, m.Author.Username)
|
||||
d.tokens[m.Author.ID] = token
|
||||
user := d.MustGetUser(channel.ID, m.Author.ID, m.Author.Discriminator, m.Author.Username)
|
||||
d.users[m.Author.ID] = user
|
||||
content := d.app.storage.lang.Telegram[lang].Strings.get("startMessage") + "\n"
|
||||
content += d.app.storage.lang.Telegram[lang].Strings.template("languageMessage", tmpl{"command": "!lang"})
|
||||
_, err = s.ChannelMessageSend(channel.ID, content)
|
||||
@ -139,7 +172,7 @@ func (d *DiscordDaemon) commandLang(s *dg.Session, m *dg.MessageCreate, sects []
|
||||
return
|
||||
}
|
||||
if _, ok := d.app.storage.lang.Telegram[sects[1]]; ok {
|
||||
d.languages[m.Author.ID] = sects[1]
|
||||
var user DiscordUser
|
||||
for jfID, user := range d.app.storage.discord {
|
||||
if user.ID == m.Author.ID {
|
||||
user.Lang = sects[1]
|
||||
@ -150,30 +183,69 @@ func (d *DiscordDaemon) commandLang(s *dg.Session, m *dg.MessageCreate, sects []
|
||||
break
|
||||
}
|
||||
}
|
||||
d.users[m.Author.ID] = user
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DiscordDaemon) commandPIN(s *dg.Session, m *dg.MessageCreate, sects []string, lang string) {
|
||||
token, ok := d.tokens[m.Author.ID]
|
||||
if !ok || token.Token != sects[0] {
|
||||
_, err := s.ChannelMessageSendReply(
|
||||
if _, ok := d.users[m.Author.ID]; ok {
|
||||
channel, err := s.Channel(m.ChannelID)
|
||||
if err != nil {
|
||||
d.app.err.Printf("Discord: Failed to get channel: %v", err)
|
||||
return
|
||||
}
|
||||
if channel.Type != dg.ChannelTypeDM {
|
||||
d.app.debug.Println("Discord: Ignoring message as not a DM")
|
||||
return
|
||||
}
|
||||
} else {
|
||||
d.app.debug.Println("Discord: Ignoring message as user was not found")
|
||||
return
|
||||
}
|
||||
tokenIndex := -1
|
||||
for i, token := range d.tokens {
|
||||
if sects[0] == token {
|
||||
tokenIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if tokenIndex == -1 {
|
||||
_, err := s.ChannelMessageSend(
|
||||
m.ChannelID,
|
||||
d.app.storage.lang.Telegram[lang].Strings.get("invalidPIN"),
|
||||
m.Reference(),
|
||||
)
|
||||
if err != nil {
|
||||
d.app.err.Printf("Discord: Failed to send message to \"%s\": %v", m.Author.Username, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
_, err := s.ChannelMessageSendReply(
|
||||
_, err := s.ChannelMessageSend(
|
||||
m.ChannelID,
|
||||
d.app.storage.lang.Telegram[lang].Strings.get("pinSuccess"),
|
||||
m.Reference(),
|
||||
)
|
||||
if err != nil {
|
||||
d.app.err.Printf("Discord: Failed to send message to \"%s\": %v", m.Author.Username, err)
|
||||
}
|
||||
d.verifiedTokens = append(d.verifiedTokens, token)
|
||||
delete(d.tokens, m.Author.ID)
|
||||
d.verifiedTokens[sects[0]] = d.users[m.Author.ID]
|
||||
d.tokens[len(d.tokens)-1], d.tokens[tokenIndex] = d.tokens[tokenIndex], d.tokens[len(d.tokens)-1]
|
||||
d.tokens = d.tokens[:len(d.tokens)-1]
|
||||
}
|
||||
|
||||
func (d *DiscordDaemon) Send(message *Message, channelID ...string) error {
|
||||
for _, id := range channelID {
|
||||
msg := ""
|
||||
if message.Markdown == "" {
|
||||
msg = message.Text
|
||||
} else {
|
||||
msg = message.Markdown
|
||||
}
|
||||
_, err := d.bot.ChannelMessageSend(
|
||||
id,
|
||||
msg,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
22
email.go
22
email.go
@ -230,7 +230,7 @@ func (emailer *Emailer) construct(app *appContext, section, keyFragment string,
|
||||
var keys []string
|
||||
plaintext := app.config.Section("email").Key("plaintext").MustBool(false)
|
||||
if plaintext {
|
||||
if telegramEnabled {
|
||||
if telegramEnabled || discordEnabled {
|
||||
keys = []string{"text"}
|
||||
text, markdown = "", ""
|
||||
} else {
|
||||
@ -238,7 +238,7 @@ func (emailer *Emailer) construct(app *appContext, section, keyFragment string,
|
||||
text = ""
|
||||
}
|
||||
} else {
|
||||
if telegramEnabled {
|
||||
if telegramEnabled || discordEnabled {
|
||||
keys = []string{"html", "text", "markdown"}
|
||||
} else {
|
||||
keys = []string{"html", "text"}
|
||||
@ -807,8 +807,21 @@ func (app *appContext) sendByID(email *Message, ID ...string) error {
|
||||
var err error
|
||||
if tgChat, ok := app.storage.telegram[id]; ok && tgChat.Contact && telegramEnabled {
|
||||
err = app.telegram.Send(email, tgChat.ChatID)
|
||||
} else if address, ok := app.storage.emails[id]; ok {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if dcChat, ok := app.storage.discord[id]; ok && dcChat.Contact && discordEnabled {
|
||||
err = app.discord.Send(email, dcChat.ChannelID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if address, ok := app.storage.emails[id]; ok {
|
||||
err = app.email.send(email, address.(string))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
@ -818,6 +831,9 @@ func (app *appContext) sendByID(email *Message, ID ...string) error {
|
||||
}
|
||||
|
||||
func (app *appContext) getAddressOrName(jfID string) string {
|
||||
if dcChat, ok := app.storage.discord[jfID]; ok && dcChat.Contact && discordEnabled {
|
||||
return dcChat.Username + "#" + dcChat.Discriminator
|
||||
}
|
||||
if tgChat, ok := app.storage.telegram[jfID]; ok && tgChat.Contact && telegramEnabled {
|
||||
return "@" + tgChat.Username
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
window.notificationsEnabled = {{ .notifications }};
|
||||
window.emailEnabled = {{ .email_enabled }};
|
||||
window.telegramEnabled = {{ .telegram_enabled }};
|
||||
window.discordEnabled = {{ .discord_enabled }};
|
||||
window.ombiEnabled = {{ .ombiEnabled }};
|
||||
window.usernameEnabled = {{ .username }};
|
||||
window.langFile = JSON.parse({{ .language }});
|
||||
@ -525,6 +526,9 @@
|
||||
{{ if .telegram_enabled }}
|
||||
<th>Telegram</th>
|
||||
{{ end }}
|
||||
{{ if .discord_enabled }}
|
||||
<th>Discord</th>
|
||||
{{ end }}
|
||||
<th>{{ .strings.expiry }}</th>
|
||||
<th>{{ .strings.lastActiveTime }}</th>
|
||||
</tr>
|
||||
|
@ -17,6 +17,9 @@
|
||||
window.telegramEnabled = {{ .telegramEnabled }};
|
||||
window.telegramRequired = {{ .telegramRequired }};
|
||||
window.telegramPIN = "{{ .telegramPIN }}";
|
||||
window.discordEnabled = {{ .discordEnabled }};
|
||||
window.discordRequired = {{ .discordRequired }};
|
||||
window.discordPIN = "{{ .discordPIN }}";
|
||||
</script>
|
||||
<script src="js/form.js" type="module"></script>
|
||||
{{ end }}
|
||||
|
@ -37,6 +37,16 @@
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ if .discordEnabled }}
|
||||
<div id="modal-discord" class="modal">
|
||||
<div class="modal-content card">
|
||||
<span class="heading mb-1">{{ .strings.linkDiscord }}</span>
|
||||
<p class="content mb-1"> {{ .discordSendPINMessage }}</p>
|
||||
<h1 class="ac">{{ .discordPIN }}</h1>
|
||||
<span class="button ~info !normal full-width center mt-1" id="discord-waiting">{{ .strings.success }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
<span class="dropdown" tabindex="0" id="lang-dropdown">
|
||||
<span class="button ~urge dropdown-button">
|
||||
<i class="ri-global-line"></i>
|
||||
@ -69,13 +79,25 @@
|
||||
<input type="email" class="input ~neutral !high mt-half mb-1" placeholder="{{ .strings.emailAddress }}" id="create-email" aria-label="{{ .strings.emailAddress }}" value="{{ .email }}">
|
||||
{{ if .telegramEnabled }}
|
||||
<span class="button ~info !normal full-width center mb-1" id="link-telegram">{{ .strings.linkTelegram }}</span>
|
||||
{{ end }}
|
||||
{{ if .discordEnabled }}
|
||||
<span class="button ~info !normal full-width center mb-1" id="link-discord">{{ .strings.linkDiscord }}</span>
|
||||
{{ end }}
|
||||
{{ if or (.telegramEnabled) (.discordEnabled) }}
|
||||
<div id="contact-via" class="unfocused">
|
||||
<label class="row switch pb-1">
|
||||
<input type="radio" name="contact-via" value="email"><span>Contact through Email</span>
|
||||
</label>
|
||||
{{ if .telegramEnabled }}
|
||||
<label class="row switch pb-1">
|
||||
<input type="radio" name="contact-via" value="telegram" id="contact-via-telegram"><span>Contact through Telegram</span>
|
||||
</label>
|
||||
{{ end }}
|
||||
{{ if .discordEnabled }}
|
||||
<label class="row switch pb-1">
|
||||
<input type="radio" name="contact-via" value="discord" id="contact-via-discord"><span>Contact through Discord</span>
|
||||
</label>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
<label class="label supra" for="create-password">{{ .strings.password }}</label>
|
||||
|
@ -17,6 +17,8 @@
|
||||
"linkTelegram": "Link Telegram",
|
||||
"contactEmail": "Contact through Email",
|
||||
"contactTelegram": "Contact through Telegram",
|
||||
"linkDiscord": "Link Discord",
|
||||
"contactDiscord": "Contact through Discord",
|
||||
"theme": "Theme"
|
||||
}
|
||||
}
|
||||
|
@ -18,14 +18,16 @@
|
||||
"confirmationRequired": "Email confirmation required",
|
||||
"confirmationRequiredMessage": "Please check your email inbox to verify your address.",
|
||||
"yourAccountIsValidUntil": "Your account will be valid until {date}.",
|
||||
"sendPIN": "Send the PIN below to the bot, then come back here to link your account."
|
||||
"sendPIN": "Send the PIN below to the bot, then come back here to link your account.",
|
||||
"sendPINDiscord": "Type {command} in {server_channel} on Discord, then send the PIN below via DM to the bot."
|
||||
},
|
||||
"notifications": {
|
||||
"errorUserExists": "User already exists.",
|
||||
"errorInvalidCode": "Invalid invite code.",
|
||||
"errorTelegramVerification": "Telegram verification required.",
|
||||
"errorInvalidPIN": "Telegram PIN is invalid.",
|
||||
"telegramVerified": "Telegram account verified."
|
||||
"errorDiscordVerification": "Discord verification required.",
|
||||
"errorInvalidPIN": "PIN is invalid.",
|
||||
"verified": "Account verified."
|
||||
},
|
||||
"validationStrings": {
|
||||
"length": {
|
||||
|
10
models.go
10
models.go
@ -17,6 +17,8 @@ type newUserDTO struct {
|
||||
Code string `json:"code" example:"abc0933jncjkcjj"` // Invite code (required on /newUser)
|
||||
TelegramPIN string `json:"telegram_pin" example:"A1-B2-3C"` // Telegram verification PIN (if used)
|
||||
TelegramContact bool `json:"telegram_contact"` // Whether or not to use telegram for notifications/pwrs
|
||||
DiscordPIN string `json:"discord_pin" example:"A1-B2-3C"` // Discord verification PIN (if used)
|
||||
DiscordContact bool `json:"discord_contact"` // Whether or not to use discord for notifications/pwrs
|
||||
}
|
||||
|
||||
type newUserResponse struct {
|
||||
@ -125,12 +127,16 @@ type respUser struct {
|
||||
ID string `json:"id" example:"fdgsdfg45534fa"` // userID of user
|
||||
Name string `json:"name" example:"jeff"` // Username of user
|
||||
Email string `json:"email,omitempty" example:"jeff@jellyf.in"` // Email address of user (if available)
|
||||
NotifyThroughEmail bool `json:"notify_email"`
|
||||
LastActive int64 `json:"last_active" example:"1617737207510"` // Time of last activity on Jellyfin
|
||||
Admin bool `json:"admin" example:"false"` // Whether or not the user is Administrator
|
||||
Expiry int64 `json:"expiry" example:"1617737207510"` // Expiry time of user as Epoch/Unix time.
|
||||
Disabled bool `json:"disabled"` // Whether or not the user is disabled.
|
||||
Telegram string `json:"telegram"` // Telegram username (if known)
|
||||
NotifyThroughTelegram bool `json:"notify_telegram"`
|
||||
Discord string `json:"discord"` // Discord username (if known)
|
||||
DiscordID string `json:"discord_id"` // Discord user ID for creating links.
|
||||
NotifyThroughDiscord bool `json:"notify_discord"`
|
||||
}
|
||||
|
||||
type getUsersDTO struct {
|
||||
@ -251,5 +257,7 @@ type telegramSetDTO struct {
|
||||
|
||||
type telegramNotifyDTO struct {
|
||||
ID string `json:"id"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Email bool `json:"email"`
|
||||
Discord bool `json:"discord"`
|
||||
Telegram bool `json:"telegram"`
|
||||
}
|
||||
|
@ -121,6 +121,9 @@ func (app *appContext) loadRoutes(router *gin.Engine) {
|
||||
if telegramEnabled {
|
||||
router.GET(p+"/invite/:invCode/telegram/verified/:pin", app.TelegramVerifiedInvite)
|
||||
}
|
||||
if discordEnabled {
|
||||
router.GET(p+"/invite/:invCode/discord/verified/:pin", app.DiscordVerifiedInvite)
|
||||
}
|
||||
}
|
||||
if *SWAGGER {
|
||||
app.info.Print(warning("\n\nWARNING: Swagger should not be used on a public instance.\n\n"))
|
||||
@ -162,7 +165,7 @@ func (app *appContext) loadRoutes(router *gin.Engine) {
|
||||
api.GET(p+"/telegram/pin", app.TelegramGetPin)
|
||||
api.GET(p+"/telegram/verified/:pin", app.TelegramVerified)
|
||||
api.POST(p+"/users/telegram", app.TelegramAddUser)
|
||||
api.POST(p+"/users/telegram/notify", app.TelegramSetNotify)
|
||||
api.POST(p+"/users/contact", app.SetContactMethods)
|
||||
}
|
||||
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
||||
api.GET(p+"/ombi/users", app.OmbiUsers)
|
||||
|
@ -42,6 +42,7 @@ type DiscordUser struct {
|
||||
ChannelID string
|
||||
ID string
|
||||
Username string
|
||||
Discriminator string
|
||||
Lang string
|
||||
Contact bool
|
||||
}
|
||||
|
55
ts/form.ts
55
ts/form.ts
@ -8,12 +8,16 @@ interface formWindow extends Window {
|
||||
invalidPassword: string;
|
||||
successModal: Modal;
|
||||
telegramModal: Modal;
|
||||
discordModal: Modal;
|
||||
confirmationModal: Modal
|
||||
code: string;
|
||||
messages: { [key: string]: string };
|
||||
confirmation: boolean;
|
||||
telegramRequired: boolean;
|
||||
telegramPIN: string;
|
||||
discordRequired: boolean;
|
||||
discordPIN: string;
|
||||
discordStartCommand: string;
|
||||
userExpiryEnabled: boolean;
|
||||
userExpiryMonths: number;
|
||||
userExpiryDays: number;
|
||||
@ -68,7 +72,7 @@ if (window.telegramEnabled) {
|
||||
telegramVerified = true;
|
||||
waiting.classList.add("~positive");
|
||||
waiting.classList.remove("~info");
|
||||
window.notifications.customPositive("telegramVerified", "", window.messages["telegramVerified"]);
|
||||
window.notifications.customPositive("telegramVerified", "", window.messages["verified"]);
|
||||
setTimeout(window.telegramModal.close, 2000);
|
||||
telegramButton.classList.add("unfocused");
|
||||
document.getElementById("contact-via").classList.remove("unfocused");
|
||||
@ -84,6 +88,46 @@ if (window.telegramEnabled) {
|
||||
};
|
||||
}
|
||||
|
||||
var discordVerified = false;
|
||||
if (window.discordEnabled) {
|
||||
window.discordModal = new Modal(document.getElementById("modal-discord"), window.discordRequired);
|
||||
const discordButton = document.getElementById("link-discord") as HTMLSpanElement;
|
||||
discordButton.onclick = () => {
|
||||
const waiting = document.getElementById("discord-waiting") as HTMLSpanElement;
|
||||
toggleLoader(waiting);
|
||||
window.discordModal.show();
|
||||
let modalClosed = false;
|
||||
window.discordModal.onclose = () => {
|
||||
modalClosed = true;
|
||||
toggleLoader(waiting);
|
||||
}
|
||||
const checkVerified = () => _get("/invite/" + window.code + "/discord/verified/" + window.discordPIN, null, (req: XMLHttpRequest) => {
|
||||
if (req.readyState == 4) {
|
||||
if (req.status == 401) {
|
||||
window.discordModal.close();
|
||||
window.notifications.customError("invalidCodeError", window.messages["errorInvalidCode"]);
|
||||
return;
|
||||
} else if (req.status == 200) {
|
||||
if (req.response["success"] as boolean) {
|
||||
discordVerified = true;
|
||||
waiting.classList.add("~positive");
|
||||
waiting.classList.remove("~info");
|
||||
window.notifications.customPositive("discordVerified", "", window.messages["verified"]);
|
||||
setTimeout(window.discordModal.close, 2000);
|
||||
discordButton.classList.add("unfocused");
|
||||
document.getElementById("contact-via").classList.remove("unfocused");
|
||||
const radio = document.getElementById("contact-via-discord") as HTMLInputElement;
|
||||
radio.checked = true;
|
||||
} else if (!modalClosed) {
|
||||
setTimeout(checkVerified, 1500);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
checkVerified();
|
||||
};
|
||||
}
|
||||
|
||||
if (window.confirmation) {
|
||||
window.confirmationModal = new Modal(document.getElementById("modal-confirmation"), true);
|
||||
}
|
||||
@ -161,6 +205,8 @@ interface sendDTO {
|
||||
password: string;
|
||||
telegram_pin?: string;
|
||||
telegram_contact?: boolean;
|
||||
discord_pin?: string;
|
||||
discord_contact?: boolean;
|
||||
}
|
||||
|
||||
const create = (event: SubmitEvent) => {
|
||||
@ -179,6 +225,13 @@ const create = (event: SubmitEvent) => {
|
||||
send.telegram_contact = true;
|
||||
}
|
||||
}
|
||||
if (discordVerified) {
|
||||
send.discord_pin = window.discordPIN;
|
||||
const radio = document.getElementById("contact-via-discord") as HTMLInputElement;
|
||||
if (radio.checked) {
|
||||
send.discord_contact = true;
|
||||
}
|
||||
}
|
||||
_post("/newUser", send, (req: XMLHttpRequest) => {
|
||||
if (req.readyState == 4) {
|
||||
let vals = req.response as respDTO;
|
||||
|
@ -7,12 +7,16 @@ interface User {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string | undefined;
|
||||
notify_email: boolean;
|
||||
last_active: number;
|
||||
admin: boolean;
|
||||
disabled: boolean;
|
||||
expiry: number;
|
||||
telegram: string;
|
||||
notify_telegram: boolean;
|
||||
discord: string;
|
||||
notify_discord: boolean;
|
||||
discord_id: string;
|
||||
}
|
||||
|
||||
interface getPinResponse {
|
||||
@ -27,11 +31,16 @@ class user implements User {
|
||||
private _admin: HTMLSpanElement;
|
||||
private _disabled: HTMLSpanElement;
|
||||
private _email: HTMLInputElement;
|
||||
private _notifyEmail: boolean;
|
||||
private _emailAddress: string;
|
||||
private _emailEditButton: HTMLElement;
|
||||
private _telegram: HTMLTableDataCellElement;
|
||||
private _telegramUsername: string;
|
||||
private _notifyTelegram: boolean;
|
||||
private _discord: HTMLTableDataCellElement;
|
||||
private _discordUsername: string;
|
||||
private _discordID: string;
|
||||
private _notifyDiscord: boolean;
|
||||
private _expiry: HTMLTableDataCellElement;
|
||||
private _expiryUnix: number;
|
||||
private _lastActive: HTMLTableDataCellElement;
|
||||
@ -82,6 +91,19 @@ class user implements User {
|
||||
}
|
||||
}
|
||||
|
||||
get notify_email(): boolean { return this._notifyEmail; }
|
||||
set notify_email(s: boolean) {
|
||||
this._notifyEmail = s;
|
||||
if (window.telegramEnabled && this._telegramUsername != "") {
|
||||
const email = this._telegram.getElementsByClassName("accounts-contact-email")[0] as HTMLInputElement;
|
||||
email.checked = s;
|
||||
}
|
||||
if (window.discordEnabled && this._discordUsername != "") {
|
||||
const email = this._discord.getElementsByClassName("accounts-contact-email")[0] as HTMLInputElement;
|
||||
email.checked = s;
|
||||
}
|
||||
}
|
||||
|
||||
get telegram(): string { return this._telegramUsername; }
|
||||
set telegram(u: string) {
|
||||
if (!window.telegramEnabled) return;
|
||||
@ -90,7 +112,7 @@ class user implements User {
|
||||
this._telegram.innerHTML = `<span class="chip btn !low">Add</span>`;
|
||||
(this._telegram.querySelector("span") as HTMLSpanElement).onclick = this._addTelegram;
|
||||
} else {
|
||||
this._telegram.innerHTML = `
|
||||
let innerHTML = `
|
||||
<a href="https://t.me/${u}" target="_blank">@${u}</a>
|
||||
<i class="icon ri-settings-2-line ml-half dropdown-button"></i>
|
||||
<div class="dropdown manual">
|
||||
@ -98,23 +120,34 @@ class user implements User {
|
||||
<div class="card ~neutral !low">
|
||||
<span class="supra sm">${window.lang.strings("contactThrough")}</span>
|
||||
<label class="switch pb-1 mt-half">
|
||||
<input type="radio" name="accounts-contact-${this.id}" class="accounts-contact-email">
|
||||
<input type="checkbox" name="accounts-contact-${this.id}" class="accounts-contact-email">
|
||||
<span>Email</span>
|
||||
</label>
|
||||
<label class="switch pb-1">
|
||||
<input type="radio" name="accounts-contact-${this.id}">
|
||||
<input type="checkbox" name="accounts-contact-${this.id}" class="accounts-contact-telegram">
|
||||
<span>Telegram</span>
|
||||
</label>
|
||||
`;
|
||||
if (window.discordEnabled && this._discordUsername != "") {
|
||||
innerHTML += `
|
||||
<label class="switch pb-1">
|
||||
<input type="checkbox" name="accounts-contact-${this.id}" class="accounts-contact-discord">
|
||||
<span>Discord</span>
|
||||
</label>
|
||||
`;
|
||||
}
|
||||
innerHTML += `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
this._discord.innerHTML = innerHTML;
|
||||
// Javascript is necessary as including the button inside the dropdown would make it too wide to display next to the username.
|
||||
const button = this._telegram.querySelector("i");
|
||||
const dropdown = this._telegram.querySelector("div.dropdown") as HTMLDivElement;
|
||||
const radios = this._telegram.querySelectorAll("input") as NodeListOf<HTMLInputElement>;
|
||||
for (let i = 0; i < radios.length; i++) {
|
||||
radios[i].onclick = this._setTelegramNotify;
|
||||
const checks = this._telegram.querySelectorAll("input") as NodeListOf<HTMLInputElement>;
|
||||
for (let i = 0; i < checks.length; i++) {
|
||||
checks[i].onclick = () => this._setNotifyMethod("telegram");
|
||||
}
|
||||
|
||||
button.onclick = () => {
|
||||
@ -134,37 +167,129 @@ class user implements User {
|
||||
set notify_telegram(s: boolean) {
|
||||
if (!window.telegramEnabled || !this._telegramUsername) return;
|
||||
this._notifyTelegram = s;
|
||||
const radios = this._telegram.querySelectorAll("input") as NodeListOf<HTMLInputElement>;
|
||||
radios[0].checked = !s;
|
||||
radios[1].checked = s;
|
||||
const telegram = this._telegram.getElementsByClassName("accounts-contact-telegram")[0] as HTMLInputElement;
|
||||
telegram.checked = s;
|
||||
if (window.discordEnabled && this._discordUsername != "") {
|
||||
const telegram = this._discord.getElementsByClassName("accounts-contact-telegram")[0] as HTMLInputElement;
|
||||
telegram.checked = s;
|
||||
}
|
||||
}
|
||||
|
||||
private _setTelegramNotify = () => {
|
||||
const radios = this._telegram.querySelectorAll("input") as NodeListOf<HTMLInputElement>;
|
||||
private _setNotifyMethod = (mode: string = "telegram") => {
|
||||
let el: HTMLElement;
|
||||
if (mode == "telegram") { el = this._telegram }
|
||||
else if (mode == "discord") { el = this._discord }
|
||||
const email = el.getElementsByClassName("accounts-contact-email")[0] as HTMLInputElement;
|
||||
let send = {
|
||||
id: this.id,
|
||||
enabled: radios[1].checked
|
||||
};
|
||||
_post("/users/telegram/notify", send, (req: XMLHttpRequest) => {
|
||||
email: email.checked
|
||||
}
|
||||
if (window.telegramEnabled && this._telegramUsername != "") {
|
||||
const telegram = el.getElementsByClassName("accounts-contact-telegram")[0] as HTMLInputElement;
|
||||
send["telegram"] = telegram.checked;
|
||||
}
|
||||
if (window.discordEnabled && this._discordUsername != "") {
|
||||
const discord = el.getElementsByClassName("accounts-contact-discord")[0] as HTMLInputElement;
|
||||
send["discord"] = discord.checked;
|
||||
}
|
||||
_post("/users/contact", send, (req: XMLHttpRequest) => {
|
||||
if (req.readyState == 4) {
|
||||
if (req.status != 200) {
|
||||
window.notifications.customError("errorSetTelegramNotify", window.lang.notif("errorSaveSettings"));
|
||||
radios[0].checked, radios[1].checked= radios[1].checked, radios[0].checked;
|
||||
window.notifications.customError("errorSetNotify", window.lang.notif("errorSaveSettings"));
|
||||
document.dispatchEvent(new CustomEvent("accounts-reload"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, false, (req: XMLHttpRequest) => {
|
||||
if (req.status == 0) {
|
||||
window.notifications.connectionError();
|
||||
radios[0].checked, radios[1].checked= radios[1].checked, radios[0].checked;
|
||||
document.dispatchEvent(new CustomEvent("accounts-reload"));
|
||||
return;
|
||||
} else if (req.status == 401) {
|
||||
radios[0].checked, radios[1].checked= radios[1].checked, radios[0].checked;
|
||||
window.notifications.customError("401Error", window.lang.notif("error401Unauthorized"));
|
||||
document.dispatchEvent(new CustomEvent("accounts-reload"));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get discord(): string { return this._discordUsername; }
|
||||
set discord(u: string) {
|
||||
if (!window.discordEnabled) return;
|
||||
this._discordUsername = u;
|
||||
if (u == "") {
|
||||
this._discord.innerHTML = `<span class="chip btn !low">Add</span>`;
|
||||
// (this._discord.querySelector("span") as HTMLSpanElement).onclick = this._addDiscord;
|
||||
} else {
|
||||
let innerHTML = `
|
||||
<a href="https://discord.com/users/${this._discordID}" class="discord-link" target="_blank">@${u}</a>
|
||||
<i class="icon ri-settings-2-line ml-half dropdown-button"></i>
|
||||
<div class="dropdown manual">
|
||||
<div class="dropdown-display">
|
||||
<div class="card ~neutral !low">
|
||||
<span class="supra sm">${window.lang.strings("contactThrough")}</span>
|
||||
<label class="switch pb-1 mt-half">
|
||||
<input type="radio" name="accounts-contact-${this.id}" class="accounts-contact-email">
|
||||
<span>Email</span>
|
||||
</label>
|
||||
<label class="switch pb-1">
|
||||
<input type="radio" name="accounts-contact-${this.id}" class="accounts-contact-discord">
|
||||
<span>Discord</span>
|
||||
</label>
|
||||
`;
|
||||
if (window.telegramEnabled && this._telegramUsername != "") {
|
||||
innerHTML += `
|
||||
<label class="switch pb-1">
|
||||
<input type="radio" name="accounts-contact-${this.id}" class="accounts-contact-telegram">
|
||||
<span>Telegram</span>
|
||||
</label>
|
||||
`;
|
||||
}
|
||||
innerHTML += `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
this._discord.innerHTML = innerHTML;
|
||||
// Javascript is necessary as including the button inside the dropdown would make it too wide to display next to the username.
|
||||
const button = this._discord.querySelector("i");
|
||||
const dropdown = this._discord.querySelector("div.dropdown") as HTMLDivElement;
|
||||
const checks = this._discord.querySelectorAll("input") as NodeListOf<HTMLInputElement>;
|
||||
for (let i = 0; i < checks.length; i++) {
|
||||
checks[i].onclick = () => this._setNotifyMethod("discord");
|
||||
}
|
||||
|
||||
button.onclick = () => {
|
||||
dropdown.classList.add("selected");
|
||||
document.addEventListener("click", outerClickListener);
|
||||
};
|
||||
const outerClickListener = (event: Event) => {
|
||||
if (!(event.target instanceof HTMLElement && (this._discord.contains(event.target) || button.contains(event.target)))) {
|
||||
dropdown.classList.remove("selected");
|
||||
document.removeEventListener("click", outerClickListener);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
get discord_id(): string { return this._discordID; }
|
||||
set discord_id(id: string) {
|
||||
this._discordID = id;
|
||||
const link = this._discord.getElementsByClassName("discord-link")[0] as HTMLAnchorElement;
|
||||
link.href = `https://discord.com/users/${id}`;
|
||||
}
|
||||
|
||||
get notify_discord(): boolean { return this._notifyDiscord; }
|
||||
set notify_discord(s: boolean) {
|
||||
if (!window.discordEnabled || !this._discordUsername) return;
|
||||
this._notifyDiscord = s;
|
||||
const discord = this._discord.getElementsByClassName("accounts-contact-discord")[0] as HTMLInputElement;
|
||||
discord.checked = s;
|
||||
if (window.telegramEnabled && this._telegramUsername != "") {
|
||||
const discord = this._discord.getElementsByClassName("accounts-contact-discord")[0] as HTMLInputElement;
|
||||
discord.checked = s;
|
||||
}
|
||||
}
|
||||
|
||||
get expiry(): number { return this._expiryUnix; }
|
||||
set expiry(unix: number) {
|
||||
this._expiryUnix = unix;
|
||||
@ -200,6 +325,11 @@ class user implements User {
|
||||
<td class="accounts-telegram"></td>
|
||||
`;
|
||||
}
|
||||
if (window.discordEnabled) {
|
||||
innerHTML += `
|
||||
<td class="accounts-discord"></td>
|
||||
`;
|
||||
}
|
||||
innerHTML += `
|
||||
<td class="accounts-expiry"></td>
|
||||
<td class="accounts-last-active"></td>
|
||||
@ -213,6 +343,7 @@ class user implements User {
|
||||
this._email = this._row.querySelector(".accounts-email-container") as HTMLInputElement;
|
||||
this._emailEditButton = this._row.querySelector(".accounts-email-edit") as HTMLElement;
|
||||
this._telegram = this._row.querySelector(".accounts-telegram") as HTMLTableDataCellElement;
|
||||
this._discord = this._row.querySelector(".accounts-discord") as HTMLTableDataCellElement;
|
||||
this._expiry = this._row.querySelector(".accounts-expiry") as HTMLTableDataCellElement;
|
||||
this._lastActive = this._row.querySelector(".accounts-last-active") as HTMLTableDataCellElement;
|
||||
this._check.onchange = () => { this.selected = this._check.checked; }
|
||||
@ -320,11 +451,14 @@ class user implements User {
|
||||
this.name = user.name;
|
||||
this.email = user.email || "";
|
||||
this.telegram = user.telegram;
|
||||
this.discord = user.discord;
|
||||
this.last_active = user.last_active;
|
||||
this.admin = user.admin;
|
||||
this.disabled = user.disabled;
|
||||
this.expiry = user.expiry;
|
||||
this.notify_telegram = user.notify_telegram;
|
||||
this.notify_discord = user.notify_discord;
|
||||
this.notify_email = user.notify_email;
|
||||
}
|
||||
|
||||
asElement = (): HTMLTableRowElement => { return this._row; }
|
||||
|
@ -21,6 +21,7 @@ declare interface Window {
|
||||
notificationsEnabled: boolean;
|
||||
emailEnabled: boolean;
|
||||
telegramEnabled: boolean;
|
||||
discordEnabled: boolean;
|
||||
ombiEnabled: boolean;
|
||||
usernameEnabled: boolean;
|
||||
token: string;
|
||||
|
19
views.go
19
views.go
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@ -121,6 +122,7 @@ func (app *appContext) AdminPage(gc *gin.Context) {
|
||||
"contactMessage": "",
|
||||
"email_enabled": emailEnabled,
|
||||
"telegram_enabled": telegramEnabled,
|
||||
"discord_enabled": discordEnabled,
|
||||
"notifications": notificationsEnabled,
|
||||
"version": version,
|
||||
"commit": commit,
|
||||
@ -284,13 +286,28 @@ func (app *appContext) InviteProxy(gc *gin.Context) {
|
||||
"userExpiryMessage": app.storage.lang.Form[lang].Strings.get("yourAccountIsValidUntil"),
|
||||
"langName": lang,
|
||||
"telegramEnabled": telegramEnabled,
|
||||
"discordEnabled": discordEnabled,
|
||||
}
|
||||
if data["telegramEnabled"].(bool) {
|
||||
if telegramEnabled {
|
||||
data["telegramPIN"] = app.telegram.NewAuthToken()
|
||||
data["telegramUsername"] = app.telegram.username
|
||||
data["telegramURL"] = app.telegram.link
|
||||
data["telegramRequired"] = app.config.Section("telegram").Key("required").MustBool(false)
|
||||
}
|
||||
if discordEnabled {
|
||||
data["discordPIN"] = app.discord.NewAuthToken()
|
||||
data["discordUsername"] = app.discord.username
|
||||
data["discordRequired"] = app.config.Section("discord").Key("required").MustBool(false)
|
||||
data["discordSendPINMessage"] = template.HTML(app.storage.lang.Form[lang].Strings.template("sendPINDiscord", tmpl{
|
||||
"command": `<code class="code">` + app.config.Section("discord").Key("start_command").MustString("!start") + `</code>`,
|
||||
"server_channel": app.discord.serverChannelName,
|
||||
}))
|
||||
}
|
||||
|
||||
// if discordEnabled {
|
||||
// pin := ""
|
||||
// for _, token := range app.discord.tokens {
|
||||
// if
|
||||
gcHTML(gc, http.StatusOK, "form-loader.html", data)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user