125 lines
4.2 KiB
Go
125 lines
4.2 KiB
Go
/*
|
|
* Amsterdam Web Communities System
|
|
* Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*/
|
|
|
|
// Package email contains support for E-mail messages sent by Amsterdam.
|
|
package email
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
|
|
"git.erbosoft.com/amy/amsterdam/database"
|
|
"git.erbosoft.com/amy/amsterdam/htmlcheck"
|
|
"github.com/CloudyKit/jet/v6"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
/* AmDeliverSubscription takes a message that's just been posted to a topic and sends it to the list of subscribers
|
|
* to that topic. It's intended to be executed in a worker pool task.
|
|
* Parameters:
|
|
* ctx - Standard Go context parameter.
|
|
* comm - Community the message was posted to.
|
|
* conf - Conference the message was posted to.
|
|
* confAlias - Current alias for that conference.
|
|
* topic - Current topic the message was posted to.
|
|
* poster - User that posted the message.
|
|
* post - The message that was posted.
|
|
* text - The text of that post.
|
|
* recipUids - Array of user IDs representing recipients of E-mail messages.
|
|
* ipaddr - IP address of the poster, used for mail tracing.
|
|
*/
|
|
func AmDeliverSubscription(ctx context.Context, comm *database.Community, conf *database.Conference, confAlias string,
|
|
topic *database.Topic, poster *database.User, post *database.PostHeader, text string, recipUids []int32, ipaddr string) {
|
|
log.Debugf("AmDeliverSubscription kicked off by %s with %d mail(s) to deliver", poster.Username, len(recipUids))
|
|
|
|
// Preprocess the text and the pseud.
|
|
checker, err := htmlcheck.AmNewHTMLChecker(ctx, "mail-post")
|
|
if err != nil {
|
|
log.Errorf("AmDeliverSubscription: failed to get HTML checker (%v)", err)
|
|
return
|
|
}
|
|
var realText string
|
|
err = checker.Append(text)
|
|
if err == nil {
|
|
err = checker.Finish()
|
|
if err == nil {
|
|
realText, err = checker.Value()
|
|
}
|
|
}
|
|
if err != nil {
|
|
log.Errorf("AmDeliverSubscription: failed to process post text (%v)", err)
|
|
return
|
|
}
|
|
checker.Reset()
|
|
var realPseud string
|
|
if post.Pseud != nil {
|
|
err = checker.Append(*post.Pseud)
|
|
if err == nil {
|
|
err = checker.Finish()
|
|
if err == nil {
|
|
realPseud, err = checker.Value()
|
|
}
|
|
}
|
|
} else {
|
|
realPseud = ""
|
|
}
|
|
if err != nil {
|
|
log.Errorf("AmDeliverSubscription: failed to process post pseud (%v)", err)
|
|
return
|
|
}
|
|
|
|
// Use Jet to format the message directly. We bypass the regular formatter in formatMessage in sender.go because
|
|
// we don't want to have to format the message once per recipient.
|
|
templ, err := emailRenderer.GetTemplate("mailpost.jet")
|
|
if err != nil {
|
|
log.Errorf("AmDeliverSubscription: failed to load template (%v)", err)
|
|
return
|
|
}
|
|
vars := make(jet.VarMap)
|
|
vars.Set("userName", poster.Username)
|
|
vars.Set("communityName", comm.Name)
|
|
vars.Set("conferenceName", conf.Name)
|
|
vars.Set("topicName", topic.Name)
|
|
pl := database.AmCreatePostLinkContext(comm.Alias, comm.Id, confAlias, topic.Number)
|
|
vars.Set("topicLink", pl.AsString())
|
|
vars.Set("pseud", realPseud)
|
|
vars.Set("text", realText)
|
|
subjectSink := AmNewEmailMessage(0, "")
|
|
var textBuf bytes.Buffer
|
|
err = templ.Execute(&textBuf, vars, subjectSink)
|
|
if err != nil {
|
|
log.Errorf("AmDeliverSubscription: failed to format template (%v)", err)
|
|
return
|
|
}
|
|
sendText := textBuf.String()
|
|
|
|
// The delivery loop; build each message and send it. Note that sending a message puts the Message structure on
|
|
// the sender goroutine channel, so we have to create a new Message each time, unlike what we did in Venice.
|
|
SendLoop:
|
|
for i := range recipUids {
|
|
select {
|
|
case <-ctx.Done():
|
|
log.Errorf("AmDeliverSubscription: aborted on send loop iter %d with %v", i+1, ctx.Err())
|
|
break SendLoop
|
|
default:
|
|
if ci, err := database.AmGetContactInfoForUser(ctx, recipUids[i]); err == nil {
|
|
msg := AmNewEmailMessage(poster.Uid, ipaddr)
|
|
msg.SetSubject(subjectSink.GetSubject())
|
|
msg.SetText(sendText)
|
|
msg.AddTo(*ci.Email, ci.FullName(false))
|
|
msg.Send()
|
|
} else {
|
|
log.Warnf("AmDeliverSubscription skipped uid %d because no contact info retrieved (%v)", recipUids[i], err)
|
|
}
|
|
}
|
|
}
|
|
}
|