Add support for multiple subscribers in a single transactional message call.
This patch adds new array fields on `POST /tx`: `subscriber_emails[]`, `subscriber_ids[]`. Either of these array fields can be sent with multiple subscribers. The individual non-array fields `subscriber_id` and `subscriber_email` are deprecated. Closes #994.
This commit is contained in:
parent
5d4f1ea0ad
commit
3cfbc646e3
25 changed files with 667 additions and 586 deletions
119
cmd/tx.go
119
cmd/tx.go
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/knadh/listmonk/internal/manager"
|
"github.com/knadh/listmonk/internal/manager"
|
||||||
"github.com/knadh/listmonk/models"
|
"github.com/knadh/listmonk/models"
|
||||||
|
@ -35,58 +36,110 @@ func handleSendTxMessage(c echo.Context) error {
|
||||||
app.i18n.Ts("globals.messages.notFound", "name", fmt.Sprintf("template %d", m.TemplateID)))
|
app.i18n.Ts("globals.messages.notFound", "name", fmt.Sprintf("template %d", m.TemplateID)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the subscriber.
|
var (
|
||||||
sub, err := app.core.GetSubscriber(m.SubscriberID, "", m.SubscriberEmail)
|
num = len(m.SubscriberEmails)
|
||||||
if err != nil {
|
isEmails = true
|
||||||
return err
|
)
|
||||||
|
if len(m.SubscriberIDs) > 0 {
|
||||||
|
num = len(m.SubscriberIDs)
|
||||||
|
isEmails = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render the message.
|
notFound := []string{}
|
||||||
if err := m.Render(sub, tpl); err != nil {
|
for n := 0; n < num; n++ {
|
||||||
return echo.NewHTTPError(http.StatusBadRequest,
|
var (
|
||||||
app.i18n.Ts("globals.messages.errorFetching", "name"))
|
subID int
|
||||||
}
|
subEmail string
|
||||||
|
)
|
||||||
|
|
||||||
// Prepare the final message.
|
if !isEmails {
|
||||||
msg := manager.Message{}
|
subID = m.SubscriberIDs[n]
|
||||||
msg.Subscriber = sub
|
} else {
|
||||||
msg.To = []string{sub.Email}
|
subEmail = m.SubscriberEmails[n]
|
||||||
msg.From = m.FromEmail
|
}
|
||||||
msg.Subject = m.Subject
|
|
||||||
msg.ContentType = m.ContentType
|
|
||||||
msg.Messenger = m.Messenger
|
|
||||||
msg.Body = m.Body
|
|
||||||
|
|
||||||
// Optional headers.
|
// Get the subscriber.
|
||||||
if len(m.Headers) != 0 {
|
sub, err := app.core.GetSubscriber(subID, "", subEmail)
|
||||||
msg.Headers = make(textproto.MIMEHeader, len(m.Headers))
|
if err != nil {
|
||||||
for _, set := range m.Headers {
|
// If the subscriber is not found, log that error and move on without halting on the list.
|
||||||
for hdr, val := range set {
|
if er, ok := err.(*echo.HTTPError); ok && er.Code == http.StatusBadRequest {
|
||||||
msg.Headers.Add(hdr, val)
|
notFound = append(notFound, fmt.Sprintf("%v", er.Message))
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the message.
|
||||||
|
if err := m.Render(sub, tpl); err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusBadRequest,
|
||||||
|
app.i18n.Ts("globals.messages.errorFetching", "name"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the final message.
|
||||||
|
msg := manager.Message{}
|
||||||
|
msg.Subscriber = sub
|
||||||
|
msg.To = []string{sub.Email}
|
||||||
|
msg.From = m.FromEmail
|
||||||
|
msg.Subject = m.Subject
|
||||||
|
msg.ContentType = m.ContentType
|
||||||
|
msg.Messenger = m.Messenger
|
||||||
|
msg.Body = m.Body
|
||||||
|
|
||||||
|
// Optional headers.
|
||||||
|
if len(m.Headers) != 0 {
|
||||||
|
msg.Headers = make(textproto.MIMEHeader, len(m.Headers))
|
||||||
|
for _, set := range m.Headers {
|
||||||
|
for hdr, val := range set {
|
||||||
|
msg.Headers.Add(hdr, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.manager.PushMessage(msg); err != nil {
|
||||||
|
app.log.Printf("error sending message (%s): %v", msg.Subject, err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := app.manager.PushMessage(msg); err != nil {
|
if len(notFound) > 0 {
|
||||||
app.log.Printf("error sending message (%s): %v", msg.Subject, err)
|
return echo.NewHTTPError(http.StatusBadRequest, strings.Join(notFound, "; "))
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.JSON(http.StatusOK, okResp{true})
|
return c.JSON(http.StatusOK, okResp{true})
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateTxMessage(m models.TxMessage, app *App) (models.TxMessage, error) {
|
func validateTxMessage(m models.TxMessage, app *App) (models.TxMessage, error) {
|
||||||
if m.SubscriberEmail == "" && m.SubscriberID == 0 {
|
if len(m.SubscriberEmails) > 0 && m.SubscriberEmail != "" {
|
||||||
return m, echo.NewHTTPError(http.StatusBadRequest,
|
return m, echo.NewHTTPError(http.StatusBadRequest,
|
||||||
app.i18n.Ts("globals.messages.missingFields", "name", "subscriber_email or subscriber_id"))
|
app.i18n.Ts("globals.messages.invalidFields", "name", "do not send `subscriber_email`"))
|
||||||
|
}
|
||||||
|
if len(m.SubscriberIDs) > 0 && m.SubscriberID != 0 {
|
||||||
|
return m, echo.NewHTTPError(http.StatusBadRequest,
|
||||||
|
app.i18n.Ts("globals.messages.invalidFields", "name", "do not send `subscriber_id`"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.SubscriberEmail != "" {
|
if m.SubscriberEmail != "" {
|
||||||
em, err := app.importer.SanitizeEmail(m.SubscriberEmail)
|
m.SubscriberEmails = append(m.SubscriberEmails, m.SubscriberEmail)
|
||||||
if err != nil {
|
}
|
||||||
return m, echo.NewHTTPError(http.StatusBadRequest, err.Error())
|
|
||||||
|
if m.SubscriberID != 0 {
|
||||||
|
m.SubscriberIDs = append(m.SubscriberIDs, m.SubscriberID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len(m.SubscriberEmails) == 0 && len(m.SubscriberIDs) == 0) || (len(m.SubscriberEmails) > 0 && len(m.SubscriberIDs) > 0) {
|
||||||
|
return m, echo.NewHTTPError(http.StatusBadRequest,
|
||||||
|
app.i18n.Ts("globals.messages.invalidFields", "name", "send subscriber_emails OR subscriber_ids"))
|
||||||
|
}
|
||||||
|
|
||||||
|
for n, email := range m.SubscriberEmails {
|
||||||
|
if m.SubscriberEmail != "" {
|
||||||
|
em, err := app.importer.SanitizeEmail(email)
|
||||||
|
if err != nil {
|
||||||
|
return m, echo.NewHTTPError(http.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
m.SubscriberEmails[n] = em
|
||||||
}
|
}
|
||||||
m.SubscriberEmail = em
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.FromEmail == "" {
|
if m.FromEmail == "" {
|
||||||
|
|
|
@ -170,6 +170,7 @@
|
||||||
"globals.messages.errorUpdating": "Error en actualitzar {name}: {error}",
|
"globals.messages.errorUpdating": "Error en actualitzar {name}: {error}",
|
||||||
"globals.messages.internalError": "Error del servidor intern",
|
"globals.messages.internalError": "Error del servidor intern",
|
||||||
"globals.messages.invalidData": "Dades no vàlides",
|
"globals.messages.invalidData": "Dades no vàlides",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "ID(s) no vàlid",
|
"globals.messages.invalidID": "ID(s) no vàlid",
|
||||||
"globals.messages.invalidUUID": "UUID(s) no vàlid",
|
"globals.messages.invalidUUID": "UUID(s) no vàlid",
|
||||||
"globals.messages.missingFields": "Falten camps: {name}",
|
"globals.messages.missingFields": "Falten camps: {name}",
|
||||||
|
|
|
@ -170,6 +170,7 @@
|
||||||
"globals.messages.errorUpdating": "Chyba při aktualizaci {name}: {error}",
|
"globals.messages.errorUpdating": "Chyba při aktualizaci {name}: {error}",
|
||||||
"globals.messages.internalError": "Interní chyba serveru",
|
"globals.messages.internalError": "Interní chyba serveru",
|
||||||
"globals.messages.invalidData": "Neplatná data",
|
"globals.messages.invalidData": "Neplatná data",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "Neplatné ID",
|
"globals.messages.invalidID": "Neplatné ID",
|
||||||
"globals.messages.invalidUUID": "Neplatné UUID",
|
"globals.messages.invalidUUID": "Neplatné UUID",
|
||||||
"globals.messages.missingFields": "Chybějící pole: {name}",
|
"globals.messages.missingFields": "Chybějící pole: {name}",
|
||||||
|
|
1099
i18n/cy.json
1099
i18n/cy.json
File diff suppressed because it is too large
Load diff
|
@ -170,6 +170,7 @@
|
||||||
"globals.messages.errorUpdating": "Fehler beim Aktualisieren von {name}: {error}",
|
"globals.messages.errorUpdating": "Fehler beim Aktualisieren von {name}: {error}",
|
||||||
"globals.messages.internalError": "Interner Serverfehler",
|
"globals.messages.internalError": "Interner Serverfehler",
|
||||||
"globals.messages.invalidData": "Ungültige Daten",
|
"globals.messages.invalidData": "Ungültige Daten",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "Ungültige ID",
|
"globals.messages.invalidID": "Ungültige ID",
|
||||||
"globals.messages.invalidUUID": "Ungültige UUID",
|
"globals.messages.invalidUUID": "Ungültige UUID",
|
||||||
"globals.messages.missingFields": "Fehlende Felder: {name}",
|
"globals.messages.missingFields": "Fehlende Felder: {name}",
|
||||||
|
|
|
@ -170,6 +170,7 @@
|
||||||
"globals.messages.errorUpdating": "Error updating {name}: {error}",
|
"globals.messages.errorUpdating": "Error updating {name}: {error}",
|
||||||
"globals.messages.internalError": "Internal server error",
|
"globals.messages.internalError": "Internal server error",
|
||||||
"globals.messages.invalidData": "Invalid data",
|
"globals.messages.invalidData": "Invalid data",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "Invalid ID(s)",
|
"globals.messages.invalidID": "Invalid ID(s)",
|
||||||
"globals.messages.invalidUUID": "Invalid UUID(s)",
|
"globals.messages.invalidUUID": "Invalid UUID(s)",
|
||||||
"globals.messages.missingFields": "Missing field(s): {name}",
|
"globals.messages.missingFields": "Missing field(s): {name}",
|
||||||
|
|
|
@ -171,6 +171,7 @@
|
||||||
"globals.messages.errorUpdating": "Error actualizando {name}: {error}",
|
"globals.messages.errorUpdating": "Error actualizando {name}: {error}",
|
||||||
"globals.messages.internalError": "Error interno del servidor.",
|
"globals.messages.internalError": "Error interno del servidor.",
|
||||||
"globals.messages.invalidData": "Datos invalidos",
|
"globals.messages.invalidData": "Datos invalidos",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "ID inválido",
|
"globals.messages.invalidID": "ID inválido",
|
||||||
"globals.messages.invalidUUID": "UUID inválido",
|
"globals.messages.invalidUUID": "UUID inválido",
|
||||||
"globals.messages.missingFields": "Cambpo(s) faltantes: {name}",
|
"globals.messages.missingFields": "Cambpo(s) faltantes: {name}",
|
||||||
|
|
|
@ -171,6 +171,7 @@
|
||||||
"globals.messages.errorUpdating": "Error updating {name}: {error}",
|
"globals.messages.errorUpdating": "Error updating {name}: {error}",
|
||||||
"globals.messages.internalError": "Internal server error",
|
"globals.messages.internalError": "Internal server error",
|
||||||
"globals.messages.invalidData": "Invalid data",
|
"globals.messages.invalidData": "Invalid data",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "Invalid ID(s)",
|
"globals.messages.invalidID": "Invalid ID(s)",
|
||||||
"globals.messages.invalidUUID": "Invalid UUID(s)",
|
"globals.messages.invalidUUID": "Invalid UUID(s)",
|
||||||
"globals.messages.missingFields": "Missing field(s): {name}",
|
"globals.messages.missingFields": "Missing field(s): {name}",
|
||||||
|
|
|
@ -171,6 +171,7 @@
|
||||||
"globals.messages.errorUpdating": "Erreur lors de la mise à jour de {name} : {error}",
|
"globals.messages.errorUpdating": "Erreur lors de la mise à jour de {name} : {error}",
|
||||||
"globals.messages.internalError": "Erreur interne du serveur",
|
"globals.messages.internalError": "Erreur interne du serveur",
|
||||||
"globals.messages.invalidData": "Données invalides",
|
"globals.messages.invalidData": "Données invalides",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "ID invalide",
|
"globals.messages.invalidID": "ID invalide",
|
||||||
"globals.messages.invalidUUID": "UUID invalide",
|
"globals.messages.invalidUUID": "UUID invalide",
|
||||||
"globals.messages.missingFields": "Champ(s) manquant(s) : {name}",
|
"globals.messages.missingFields": "Champ(s) manquant(s) : {name}",
|
||||||
|
|
|
@ -171,6 +171,7 @@
|
||||||
"globals.messages.errorUpdating": "Hiba a frissítés során {name}: {error}",
|
"globals.messages.errorUpdating": "Hiba a frissítés során {name}: {error}",
|
||||||
"globals.messages.internalError": "Belső Szerverhiba",
|
"globals.messages.internalError": "Belső Szerverhiba",
|
||||||
"globals.messages.invalidData": "Érvénytelen adat",
|
"globals.messages.invalidData": "Érvénytelen adat",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "Érvénytelen ID(s)",
|
"globals.messages.invalidID": "Érvénytelen ID(s)",
|
||||||
"globals.messages.invalidUUID": "Érvénytelen UUID(s)",
|
"globals.messages.invalidUUID": "Érvénytelen UUID(s)",
|
||||||
"globals.messages.missingFields": "Hiányzó mező(k): {name}",
|
"globals.messages.missingFields": "Hiányzó mező(k): {name}",
|
||||||
|
|
|
@ -171,6 +171,7 @@
|
||||||
"globals.messages.errorUpdating": "Errore durante l'aggiornamento di {name}: {error}",
|
"globals.messages.errorUpdating": "Errore durante l'aggiornamento di {name}: {error}",
|
||||||
"globals.messages.internalError": "Errore interno nel server",
|
"globals.messages.internalError": "Errore interno nel server",
|
||||||
"globals.messages.invalidData": "Dati non validi",
|
"globals.messages.invalidData": "Dati non validi",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "ID non valido",
|
"globals.messages.invalidID": "ID non valido",
|
||||||
"globals.messages.invalidUUID": "UUID non valido",
|
"globals.messages.invalidUUID": "UUID non valido",
|
||||||
"globals.messages.missingFields": "Valore/i mancante/i: {name}",
|
"globals.messages.missingFields": "Valore/i mancante/i: {name}",
|
||||||
|
|
|
@ -171,6 +171,7 @@
|
||||||
"globals.messages.errorUpdating": "{name}更新エラー: {error}",
|
"globals.messages.errorUpdating": "{name}更新エラー: {error}",
|
||||||
"globals.messages.internalError": "内部サーバーエラー",
|
"globals.messages.internalError": "内部サーバーエラー",
|
||||||
"globals.messages.invalidData": "無効なデータ",
|
"globals.messages.invalidData": "無効なデータ",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "無効なID",
|
"globals.messages.invalidID": "無効なID",
|
||||||
"globals.messages.invalidUUID": "無効なUUID",
|
"globals.messages.invalidUUID": "無効なUUID",
|
||||||
"globals.messages.missingFields": "フィールドがありません: {name}",
|
"globals.messages.missingFields": "フィールドがありません: {name}",
|
||||||
|
|
|
@ -170,6 +170,7 @@
|
||||||
"globals.messages.errorUpdating": "{name} പുതുക്കുന്നതിൽ പിശകുണ്ടായി: {error}",
|
"globals.messages.errorUpdating": "{name} പുതുക്കുന്നതിൽ പിശകുണ്ടായി: {error}",
|
||||||
"globals.messages.internalError": "സേർവറിനു തകരാറുപറ്റി",
|
"globals.messages.internalError": "സേർവറിനു തകരാറുപറ്റി",
|
||||||
"globals.messages.invalidData": "അസാധുവായ വിവരം",
|
"globals.messages.invalidData": "അസാധുവായ വിവരം",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "ഐഡി അസാധുവാണ്",
|
"globals.messages.invalidID": "ഐഡി അസാധുവാണ്",
|
||||||
"globals.messages.invalidUUID": "യുയുഐഡി അസാധുവാണ്",
|
"globals.messages.invalidUUID": "യുയുഐഡി അസാധുവാണ്",
|
||||||
"globals.messages.missingFields": "വിട്ടുപോയ ഫീൽഡ്(കൾ): {name}",
|
"globals.messages.missingFields": "വിട്ടുപോയ ഫീൽഡ്(കൾ): {name}",
|
||||||
|
|
|
@ -171,6 +171,7 @@
|
||||||
"globals.messages.errorUpdating": "Fout bij updaten {name}: {error}",
|
"globals.messages.errorUpdating": "Fout bij updaten {name}: {error}",
|
||||||
"globals.messages.internalError": "Interne serverfout",
|
"globals.messages.internalError": "Interne serverfout",
|
||||||
"globals.messages.invalidData": "Ongeldige data",
|
"globals.messages.invalidData": "Ongeldige data",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "Ongeldige ID(s)",
|
"globals.messages.invalidID": "Ongeldige ID(s)",
|
||||||
"globals.messages.invalidUUID": "Ongeldige UUID(s)",
|
"globals.messages.invalidUUID": "Ongeldige UUID(s)",
|
||||||
"globals.messages.missingFields": "Ontbrekend(e) veld(en): {name}",
|
"globals.messages.missingFields": "Ontbrekend(e) veld(en): {name}",
|
||||||
|
|
|
@ -171,6 +171,7 @@
|
||||||
"globals.messages.errorUpdating": "Błąd podczas aktualizacji {name}: {error}",
|
"globals.messages.errorUpdating": "Błąd podczas aktualizacji {name}: {error}",
|
||||||
"globals.messages.internalError": "Internal server error",
|
"globals.messages.internalError": "Internal server error",
|
||||||
"globals.messages.invalidData": "Invalid data",
|
"globals.messages.invalidData": "Invalid data",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "Nieprawidłowy iD",
|
"globals.messages.invalidID": "Nieprawidłowy iD",
|
||||||
"globals.messages.invalidUUID": "Nieprawidłowy UUID",
|
"globals.messages.invalidUUID": "Nieprawidłowy UUID",
|
||||||
"globals.messages.missingFields": "Missing field(s): {name}",
|
"globals.messages.missingFields": "Missing field(s): {name}",
|
||||||
|
|
|
@ -170,6 +170,7 @@
|
||||||
"globals.messages.errorUpdating": "Erro ao atualizar {name}: {error}",
|
"globals.messages.errorUpdating": "Erro ao atualizar {name}: {error}",
|
||||||
"globals.messages.internalError": "Erro no servidor",
|
"globals.messages.internalError": "Erro no servidor",
|
||||||
"globals.messages.invalidData": "Dados inválidos",
|
"globals.messages.invalidData": "Dados inválidos",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "ID inválido",
|
"globals.messages.invalidID": "ID inválido",
|
||||||
"globals.messages.invalidUUID": "UUID inválido",
|
"globals.messages.invalidUUID": "UUID inválido",
|
||||||
"globals.messages.missingFields": "Campos ausente(s): {name}",
|
"globals.messages.missingFields": "Campos ausente(s): {name}",
|
||||||
|
|
|
@ -170,6 +170,7 @@
|
||||||
"globals.messages.errorUpdating": "Erro ao atualizar {name}: {error}",
|
"globals.messages.errorUpdating": "Erro ao atualizar {name}: {error}",
|
||||||
"globals.messages.internalError": "Erro interno no servidor",
|
"globals.messages.internalError": "Erro interno no servidor",
|
||||||
"globals.messages.invalidData": "Dados inválidos",
|
"globals.messages.invalidData": "Dados inválidos",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "ID inválido",
|
"globals.messages.invalidID": "ID inválido",
|
||||||
"globals.messages.invalidUUID": "UUID inválido",
|
"globals.messages.invalidUUID": "UUID inválido",
|
||||||
"globals.messages.missingFields": "Campo(s) em falta: {name}",
|
"globals.messages.missingFields": "Campo(s) em falta: {name}",
|
||||||
|
|
|
@ -171,6 +171,7 @@
|
||||||
"globals.messages.errorUpdating": "Eroare actualizare {nume}: {eroare}",
|
"globals.messages.errorUpdating": "Eroare actualizare {nume}: {eroare}",
|
||||||
"globals.messages.internalError": "Eroare server intern",
|
"globals.messages.internalError": "Eroare server intern",
|
||||||
"globals.messages.invalidData": "Date invalide",
|
"globals.messages.invalidData": "Date invalide",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "ID(uri) invalide",
|
"globals.messages.invalidID": "ID(uri) invalide",
|
||||||
"globals.messages.invalidUUID": "UUID(uri) invalide",
|
"globals.messages.invalidUUID": "UUID(uri) invalide",
|
||||||
"globals.messages.missingFields": "Camuri lipsă: {nume}",
|
"globals.messages.missingFields": "Camuri lipsă: {nume}",
|
||||||
|
|
|
@ -170,6 +170,7 @@
|
||||||
"globals.messages.errorUpdating": "Ошибка обновления {name}: {error}",
|
"globals.messages.errorUpdating": "Ошибка обновления {name}: {error}",
|
||||||
"globals.messages.internalError": "Внутренняя ошибка сервера",
|
"globals.messages.internalError": "Внутренняя ошибка сервера",
|
||||||
"globals.messages.invalidData": "Неверные данные",
|
"globals.messages.invalidData": "Неверные данные",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "Неверный ID",
|
"globals.messages.invalidID": "Неверный ID",
|
||||||
"globals.messages.invalidUUID": "Неверный UUID",
|
"globals.messages.invalidUUID": "Неверный UUID",
|
||||||
"globals.messages.missingFields": "Отсутствующее поле (поля): {name}",
|
"globals.messages.missingFields": "Отсутствующее поле (поля): {name}",
|
||||||
|
|
|
@ -147,6 +147,7 @@
|
||||||
"globals.days.4": "Per",
|
"globals.days.4": "Per",
|
||||||
"globals.days.5": "Cum",
|
"globals.days.5": "Cum",
|
||||||
"globals.days.6": "Cmt",
|
"globals.days.6": "Cmt",
|
||||||
|
"globals.days.7": "Sat",
|
||||||
"globals.fields.createdAt": "Yaratılma",
|
"globals.fields.createdAt": "Yaratılma",
|
||||||
"globals.fields.description": "Açıklama",
|
"globals.fields.description": "Açıklama",
|
||||||
"globals.fields.id": "ID",
|
"globals.fields.id": "ID",
|
||||||
|
@ -170,6 +171,7 @@
|
||||||
"globals.messages.errorUpdating": "Hata güncellerken {name}: {error}",
|
"globals.messages.errorUpdating": "Hata güncellerken {name}: {error}",
|
||||||
"globals.messages.internalError": "Sunucu hatası",
|
"globals.messages.internalError": "Sunucu hatası",
|
||||||
"globals.messages.invalidData": "Geçersiz veri",
|
"globals.messages.invalidData": "Geçersiz veri",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "Yanlış ID",
|
"globals.messages.invalidID": "Yanlış ID",
|
||||||
"globals.messages.invalidUUID": "Yanlış UUID",
|
"globals.messages.invalidUUID": "Yanlış UUID",
|
||||||
"globals.messages.missingFields": "Eksik alan(lar): {name}",
|
"globals.messages.missingFields": "Eksik alan(lar): {name}",
|
||||||
|
@ -177,6 +179,9 @@
|
||||||
"globals.messages.passwordChange": "Değiştirmek için değer gir",
|
"globals.messages.passwordChange": "Değiştirmek için değer gir",
|
||||||
"globals.messages.updated": "\"{name}\" güncellendi",
|
"globals.messages.updated": "\"{name}\" güncellendi",
|
||||||
"globals.months.1": "Oca",
|
"globals.months.1": "Oca",
|
||||||
|
"globals.months.10": "Eki",
|
||||||
|
"globals.months.11": "Kas",
|
||||||
|
"globals.months.12": "Ara",
|
||||||
"globals.months.2": "Şub",
|
"globals.months.2": "Şub",
|
||||||
"globals.months.3": "Mar",
|
"globals.months.3": "Mar",
|
||||||
"globals.months.4": "Nis",
|
"globals.months.4": "Nis",
|
||||||
|
@ -185,9 +190,6 @@
|
||||||
"globals.months.7": "Tem",
|
"globals.months.7": "Tem",
|
||||||
"globals.months.8": "Ağu",
|
"globals.months.8": "Ağu",
|
||||||
"globals.months.9": "Eyl",
|
"globals.months.9": "Eyl",
|
||||||
"globals.months.10": "Eki",
|
|
||||||
"globals.months.11": "Kas",
|
|
||||||
"globals.months.12": "Ara",
|
|
||||||
"globals.states.off": "Off",
|
"globals.states.off": "Off",
|
||||||
"globals.terms.all": "All",
|
"globals.terms.all": "All",
|
||||||
"globals.terms.analytics": "Analitik",
|
"globals.terms.analytics": "Analitik",
|
||||||
|
|
|
@ -171,6 +171,7 @@
|
||||||
"globals.messages.errorUpdating": "Lỗi khi cập nhật {name}: {error}",
|
"globals.messages.errorUpdating": "Lỗi khi cập nhật {name}: {error}",
|
||||||
"globals.messages.internalError": "Lỗi máy chủ nội bộ",
|
"globals.messages.internalError": "Lỗi máy chủ nội bộ",
|
||||||
"globals.messages.invalidData": "Dữ liệu không hợp lệ",
|
"globals.messages.invalidData": "Dữ liệu không hợp lệ",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "ID(s) không hợp lệ",
|
"globals.messages.invalidID": "ID(s) không hợp lệ",
|
||||||
"globals.messages.invalidUUID": " UUID(s) không hợp lệ",
|
"globals.messages.invalidUUID": " UUID(s) không hợp lệ",
|
||||||
"globals.messages.missingFields": "Lỗi field(s): {name}",
|
"globals.messages.missingFields": "Lỗi field(s): {name}",
|
||||||
|
|
|
@ -170,6 +170,7 @@
|
||||||
"globals.messages.errorUpdating": "更新 {name} 时出错:{error}",
|
"globals.messages.errorUpdating": "更新 {name} 时出错:{error}",
|
||||||
"globals.messages.internalError": "内部服务器错误",
|
"globals.messages.internalError": "内部服务器错误",
|
||||||
"globals.messages.invalidData": "无效数据",
|
"globals.messages.invalidData": "无效数据",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "ID 无效",
|
"globals.messages.invalidID": "ID 无效",
|
||||||
"globals.messages.invalidUUID": "无效的 UUID",
|
"globals.messages.invalidUUID": "无效的 UUID",
|
||||||
"globals.messages.missingFields": "缺少字段:{name}",
|
"globals.messages.missingFields": "缺少字段:{name}",
|
||||||
|
|
|
@ -171,6 +171,7 @@
|
||||||
"globals.messages.errorUpdating": "更新{name} 時出錯:{error}",
|
"globals.messages.errorUpdating": "更新{name} 時出錯:{error}",
|
||||||
"globals.messages.internalError": "內部服務器錯誤",
|
"globals.messages.internalError": "內部服務器錯誤",
|
||||||
"globals.messages.invalidData": "無效數據",
|
"globals.messages.invalidData": "無效數據",
|
||||||
|
"globals.messages.invalidFields": "Invalid fields: {name}",
|
||||||
"globals.messages.invalidID": "ID 無效",
|
"globals.messages.invalidID": "ID 無效",
|
||||||
"globals.messages.invalidUUID": "無效的UUID",
|
"globals.messages.invalidUUID": "無效的UUID",
|
||||||
"globals.messages.missingFields": "缺少字段:{name}",
|
"globals.messages.missingFields": "缺少字段:{name}",
|
||||||
|
|
|
@ -34,7 +34,8 @@ func (c *Core) GetSubscriber(id int, uuid, email string) (models.Subscriber, err
|
||||||
}
|
}
|
||||||
if len(out) == 0 {
|
if len(out) == 0 {
|
||||||
return models.Subscriber{}, echo.NewHTTPError(http.StatusBadRequest,
|
return models.Subscriber{}, echo.NewHTTPError(http.StatusBadRequest,
|
||||||
c.i18n.Ts("globals.messages.notFound", "name", "{globals.terms.subscriber}"))
|
c.i18n.Ts("globals.messages.notFound", "name",
|
||||||
|
fmt.Sprintf("{globals.terms.subscriber} (%d: %s%s)", id, uuid, email)))
|
||||||
}
|
}
|
||||||
if err := out.LoadLists(c.q.GetSubscriberListsLazy); err != nil {
|
if err := out.LoadLists(c.q.GetSubscriberListsLazy); err != nil {
|
||||||
c.log.Printf("error loading subscriber lists: %v", err)
|
c.log.Printf("error loading subscriber lists: %v", err)
|
||||||
|
|
|
@ -347,6 +347,10 @@ type Bounce struct {
|
||||||
|
|
||||||
// TxMessage represents an e-mail campaign.
|
// TxMessage represents an e-mail campaign.
|
||||||
type TxMessage struct {
|
type TxMessage struct {
|
||||||
|
SubscriberEmails []string `json:"subscriber_emails"`
|
||||||
|
SubscriberIDs []int `json:"subscriber_ids"`
|
||||||
|
|
||||||
|
// Deprecated.
|
||||||
SubscriberEmail string `json:"subscriber_email"`
|
SubscriberEmail string `json:"subscriber_email"`
|
||||||
SubscriberID int `json:"subscriber_id"`
|
SubscriberID int `json:"subscriber_id"`
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue