1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2024-12-22 09:00:10 +00:00

Telegram: Send messages via telegram

Most messages are now sent as plaintext via telegram when suitable.
This commit is contained in:
Harvey Tindall 2021-05-07 16:06:47 +01:00
parent 72bf280e2d
commit 716d6a931a
Signed by: hrfee
GPG Key ID: BBC65952848FB1A2
10 changed files with 118 additions and 112 deletions

104
api.go
View File

@ -282,7 +282,7 @@ func (app *appContext) NewUserAdmin(gc *gin.Context) {
}
}
app.jf.CacheExpiry = time.Now()
if app.config.Section("password_resets").Key("enabled").MustBool(false) {
if emailEnabled {
app.storage.emails[id] = req.Email
app.storage.storeEmails()
}
@ -500,15 +500,16 @@ func (app *appContext) newUser(req newUserDTO, confirmed bool) (f errorFunc, suc
}
}
if emailEnabled && app.config.Section("welcome_email").Key("enabled").MustBool(false) && req.Email != "" {
app.debug.Printf("%s: Sending welcome email to %s", req.Username, req.Email)
if (emailEnabled && app.config.Section("welcome_email").Key("enabled").MustBool(false) && req.Email != "") || telegramTokenIndex != -1 {
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)
if err != nil {
app.err.Printf("%s: Failed to construct welcome email: %v", req.Username, err)
} else if err := app.email.send(msg, req.Email); err != nil {
app.err.Printf("%s: Failed to send welcome email: %v", req.Username, err)
app.err.Printf("%s: Failed to construct welcome message: %v", req.Username, err)
} else if err := app.sendByID(msg, user.ID); err != nil {
app.err.Printf("%s: Failed to send welcome message: %v", req.Username, err)
} else {
app.info.Printf("%s: Sent welcome email to \"%s\"", req.Username, req.Email)
app.info.Printf("%s: Sent welcome message to \"%s\"", req.Username, name)
}
}
app.jf.CacheExpiry = time.Now()
@ -575,7 +576,20 @@ func (app *appContext) EnableDisableUsers(gc *gin.Context) {
"GetUser": map[string]string{},
"SetPolicy": map[string]string{},
}
var addresses []string
sendMail := emailEnabled || app.config.Section("telegram").Key("enabled").MustBool(false)
var msg *Message
var err error
if sendMail {
if req.Enabled {
msg, err = app.email.constructEnabled(req.Reason, app, false)
} else {
msg, err = app.email.constructDisabled(req.Reason, app, false)
}
if err != nil {
app.err.Printf("Failed to construct account enabled/disabled emails: %v", err)
sendMail = false
}
}
for _, userID := range req.Users {
user, status, err := app.jf.UserByID(userID, false)
if status != 200 || err != nil {
@ -590,31 +604,13 @@ func (app *appContext) EnableDisableUsers(gc *gin.Context) {
app.err.Printf("Failed to set policy for user \"%s\" (%d): %v", userID, status, err)
continue
}
if emailEnabled && req.Notify {
addr, ok := app.storage.emails[userID]
if addr != nil && ok {
addresses = append(addresses, addr.(string))
if sendMail && req.Notify {
if err := app.sendByID(msg, userID); err != nil {
app.err.Printf("Failed to send account enabled/disabled email: %v", err)
continue
}
}
}
if len(addresses) != 0 {
go func(reason string, addresses []string) {
var msg *Message
var err error
if req.Enabled {
msg, err = app.email.constructEnabled(reason, app, false)
} else {
msg, err = app.email.constructDisabled(reason, app, false)
}
if err != nil {
app.err.Printf("Failed to construct account enabled/disabled emails: %v", err)
} else if err := app.email.send(msg, addresses...); err != nil {
app.err.Printf("Failed to send account enabled/disabled emails: %v", err)
} else {
app.info.Println("Sent account enabled/disabled emails")
}
}(req.Reason, addresses)
}
app.jf.CacheExpiry = time.Now()
if len(errors["GetUser"]) != 0 || len(errors["SetPolicy"]) != 0 {
gc.JSON(500, errors)
@ -634,10 +630,19 @@ func (app *appContext) EnableDisableUsers(gc *gin.Context) {
// @tags Users
func (app *appContext) DeleteUsers(gc *gin.Context) {
var req deleteUserDTO
var addresses []string
gc.BindJSON(&req)
errors := map[string]string{}
ombiEnabled := app.config.Section("ombi").Key("enabled").MustBool(false)
sendMail := emailEnabled || app.config.Section("telegram").Key("enabled").MustBool(false)
var msg *Message
var err error
if sendMail {
msg, err = app.email.constructDeleted(req.Reason, app, false)
if err != nil {
app.err.Printf("Failed to construct account deletion emails: %v", err)
sendMail = false
}
}
for _, userID := range req.Users {
if ombiEnabled {
ombiUser, code, err := app.getOmbiUser(userID)
@ -660,25 +665,12 @@ func (app *appContext) DeleteUsers(gc *gin.Context) {
errors[userID] += msg
}
}
if emailEnabled && req.Notify {
addr, ok := app.storage.emails[userID]
if addr != nil && ok {
addresses = append(addresses, addr.(string))
if sendMail && req.Notify {
if err := app.sendByID(msg, userID); err != nil {
app.err.Printf("Failed to send account deletion email: %v", err)
}
}
}
if len(addresses) != 0 {
go func(reason string, addresses []string) {
msg, err := app.email.constructDeleted(reason, app, false)
if err != nil {
app.err.Printf("Failed to construct account deletion emails: %v", err)
} else if err := app.email.send(msg, addresses...); err != nil {
app.err.Printf("Failed to send account deletion emails: %v", err)
} else {
app.info.Println("Sent account deletion emails")
}
}(req.Reason, addresses)
}
app.jf.CacheExpiry = time.Now()
if len(errors) == len(req.Users) {
respondBool(500, false, gc)
@ -735,29 +727,21 @@ func (app *appContext) ExtendExpiry(gc *gin.Context) {
func (app *appContext) Announce(gc *gin.Context) {
var req announcementDTO
gc.BindJSON(&req)
if !emailEnabled {
if !(emailEnabled || app.config.Section("telegram").Key("enabled").MustBool(false)) {
respondBool(400, false, gc)
return
}
addresses := []string{}
for _, userID := range req.Users {
addr, ok := app.storage.emails[userID]
if !ok || addr == "" {
continue
}
addresses = append(addresses, addr.(string))
}
msg, err := app.email.constructTemplate(req.Subject, req.Message, app)
if err != nil {
app.err.Printf("Failed to construct announcement emails: %v", err)
app.err.Printf("Failed to construct announcement messages: %v", err)
respondBool(500, false, gc)
return
} else if err := app.email.send(msg, addresses...); err != nil {
app.err.Printf("Failed to send announcement emails: %v", err)
} else if err := app.sendByID(msg, req.Users...); err != nil {
app.err.Printf("Failed to send announcement messages: %v", err)
respondBool(500, false, gc)
return
}
app.info.Printf("Sent announcement email to %d users", len(addresses))
app.info.Println("Sent announcement messages")
respondBool(200, true, gc)
}

View File

@ -755,3 +755,30 @@ func (emailer *Emailer) constructUserExpired(app *appContext, noSub bool) (*Mess
func (emailer *Emailer) send(email *Message, address ...string) error {
return emailer.sender.Send(emailer.fromName, emailer.fromAddr, email, address...)
}
func (app *appContext) sendByID(email *Message, ID ...string) error {
tgEnabled := app.config.Section("telegram").Key("enabled").MustBool(false)
for _, id := range ID {
var err error
if tgChat, ok := app.storage.telegram[id]; ok && tgChat.Contact && tgEnabled {
err = app.telegram.Send(email, tgChat.ChatID)
} else if address, ok := app.storage.emails[id]; ok {
err = app.email.send(email, address.(string))
}
if err != nil {
return err
}
}
return nil
}
func (app *appContext) getAddressOrName(jfID string) string {
tgEnabled := app.config.Section("telegram").Key("enabled").MustBool(false)
if tgChat, ok := app.storage.telegram[jfID]; ok && tgChat.Contact && tgEnabled {
return "@" + tgChat.Username
}
if addr, ok := app.storage.emails[jfID]; ok {
return addr.(string)
}
return ""
}

View File

@ -6,6 +6,7 @@
window.URLBase = "{{ .urlBase }}";
window.notificationsEnabled = {{ .notifications }};
window.emailEnabled = {{ .email_enabled }};
window.telegramEnabled = {{ .telegram_enabled }};
window.ombiEnabled = {{ .ombiEnabled }};
window.usernameEnabled = {{ .username }};
window.langFile = JSON.parse({{ .language }});

View File

@ -69,27 +69,24 @@ func pwrMonitor(app *appContext, watcher *fsnotify.Watcher) {
return
}
app.storage.loadEmails()
var address string
uid := user.ID
if uid == "" {
app.err.Printf("Couldn't get user ID for user \"%s\"", pwr.Username)
return
}
addr, ok := app.storage.emails[uid]
if !ok || addr == nil {
app.err.Printf("Couldn't find email for user \"%s\". Make sure it's set", pwr.Username)
return
}
address = addr.(string)
msg, err := app.email.constructReset(pwr, app, false)
if err != nil {
app.err.Printf("Failed to construct password reset email for %s", pwr.Username)
app.debug.Printf("%s: Error: %s", pwr.Username, err)
} else if err := app.email.send(msg, address); err != nil {
app.err.Printf("Failed to send password reset email to \"%s\"", address)
app.debug.Printf("%s: Error: %s", pwr.Username, err)
} else {
app.info.Printf("Sent password reset email to \"%s\"", address)
name := app.getAddressOrName(uid)
if name != "" {
msg, err := app.email.constructReset(pwr, app, false)
if err != nil {
app.err.Printf("Failed to construct password reset message for %s", pwr.Username)
app.debug.Printf("%s: Error: %s", pwr.Username, err)
} else if err := app.sendByID(msg, uid); err != nil {
app.err.Printf("Failed to send password reset message to \"%s\"", name)
app.debug.Printf("%s: Error: %s", pwr.Username, err)
} else {
app.info.Printf("Sent password reset message to \"%s\"", name)
}
}
} else {
app.err.Printf("Password reset for user \"%s\" has already expired (%s). Check your time settings.", pwr.Username, pwr.Expiry)

View File

@ -3,7 +3,6 @@ package main
import (
"fmt"
"math/rand"
"strconv"
"strings"
"time"
@ -194,15 +193,11 @@ func (t *TelegramDaemon) QuoteReply(upd *tg.Update, content string) error {
return err
}
// Send adds compatibility with EmailClient, fromName/fromAddr are discarded, message.Text is used, addresses are Chat IDs as strings.
func (t *TelegramDaemon) Send(fromName, fromAddr string, message *Message, address ...string) error {
for _, addr := range address {
ChatID, err := strconv.ParseInt(addr, 10, 64)
if err != nil {
return err
}
msg := tg.NewMessage(ChatID, message.Text)
_, err = t.bot.Send(msg)
// Send will send a telegram message to a list of chat IDs. message.text is used.
func (t *TelegramDaemon) Send(message *Message, ID ...int64) error {
for _, id := range ID {
msg := tg.NewMessage(id, message.Text)
_, err := t.bot.Send(msg)
if err != nil {
return err
}

View File

@ -12,7 +12,6 @@ interface formWindow extends Window {
code: string;
messages: { [key: string]: string };
confirmation: boolean;
telegramEnabled: boolean;
telegramRequired: boolean;
telegramPIN: string;
userExpiryEnabled: boolean;

View File

@ -334,7 +334,7 @@ export class accountsList {
this._selectAll.checked = false;
this._modifySettings.classList.add("unfocused");
this._deleteUser.classList.add("unfocused");
if (window.emailEnabled) {
if (window.emailEnabled || window.telegramEnabled) {
this._announceButton.classList.add("unfocused");
}
this._extendExpiry.classList.add("unfocused");
@ -356,7 +356,7 @@ export class accountsList {
this._modifySettings.classList.remove("unfocused");
this._deleteUser.classList.remove("unfocused");
this._deleteUser.textContent = window.lang.quantity("deleteUser", list.length);
if (window.emailEnabled) {
if (window.emailEnabled || window.telegramEnabled) {
this._announceButton.classList.remove("unfocused");
}
let anyNonExpiries = list.length == 0 ? true : false;

View File

@ -18,6 +18,7 @@ declare interface Window {
jfUsers: Array<Object>;
notificationsEnabled: boolean;
emailEnabled: boolean;
telegramEnabled: boolean;
ombiEnabled: boolean;
usernameEnabled: boolean;
token: string;

View File

@ -71,9 +71,10 @@ func (app *appContext) checkUsers() {
mode = "delete"
termPlural = "Deleting"
}
email := false
if emailEnabled && app.config.Section("user_expiry").Key("send_email").MustBool(true) {
email = true
contact := false
if (emailEnabled && app.config.Section("user_expiry").Key("send_email").MustBool(true)) ||
app.config.Section("telegram").Key("enabled").MustBool(false) {
contact = true
}
// Use a map to speed up checking for deleted users later
userExists := map[string]bool{}
@ -114,18 +115,18 @@ func (app *appContext) checkUsers() {
}
delete(app.storage.users, id)
app.jf.CacheExpiry = time.Now()
if email {
address, ok := app.storage.emails[id]
if contact {
if !ok {
continue
}
name := app.getAddressOrName(user.ID)
msg, err := app.email.constructUserExpired(app, false)
if err != nil {
app.err.Printf("Failed to construct expiry email for \"%s\": %s", user.Name, err)
} else if err := app.email.send(msg, address.(string)); err != nil {
app.err.Printf("Failed to send expiry email to \"%s\": %s", user.Name, err)
app.err.Printf("Failed to construct expiry message for \"%s\": %s", user.Name, err)
} else if err := app.sendByID(msg, user.ID); err != nil {
app.err.Printf("Failed to send expiry message to \"%s\": %s", name, err)
} else {
app.info.Printf("Sent expiry notification to \"%s\"", address.(string))
app.info.Printf("Sent expiry notification to \"%s\"", name)
}
}
}

View File

@ -116,20 +116,21 @@ func (app *appContext) AdminPage(gc *gin.Context) {
}
license = string(l)
gcHTML(gc, http.StatusOK, "admin.html", gin.H{
"urlBase": app.getURLBase(gc),
"cssClass": app.cssClass,
"contactMessage": "",
"email_enabled": emailEnabled,
"notifications": notificationsEnabled,
"version": version,
"commit": commit,
"ombiEnabled": ombiEnabled,
"username": !app.config.Section("email").Key("no_username").MustBool(false),
"strings": app.storage.lang.Admin[lang].Strings,
"quantityStrings": app.storage.lang.Admin[lang].QuantityStrings,
"language": app.storage.lang.Admin[lang].JSON,
"langName": lang,
"license": license,
"urlBase": app.getURLBase(gc),
"cssClass": app.cssClass,
"contactMessage": "",
"email_enabled": emailEnabled,
"telegram_enabled": app.config.Section("telegram").Key("enabled").MustBool(false),
"notifications": notificationsEnabled,
"version": version,
"commit": commit,
"ombiEnabled": ombiEnabled,
"username": !app.config.Section("email").Key("no_username").MustBool(false),
"strings": app.storage.lang.Admin[lang].Strings,
"quantityStrings": app.storage.lang.Admin[lang].QuantityStrings,
"language": app.storage.lang.Admin[lang].JSON,
"langName": lang,
"license": license,
})
}