send approved/rejected emails

This commit is contained in:
tobi 2024-04-12 11:24:02 +02:00
parent e946f36601
commit 3b98e7d96c
10 changed files with 227 additions and 0 deletions

View file

@ -72,6 +72,14 @@ func (s *noopSender) SendNewSignupEmail(toAddresses []string, data NewSignupData
return s.sendTemplate(newSignupTemplate, newSignupSubject, data, toAddresses...)
}
func (s *noopSender) SendSignupApprovedEmail(toAddress string, data SignupApprovedData) error {
return s.sendTemplate(signupApprovedTemplate, signupApprovedSubject, data, toAddress)
}
func (s *noopSender) SendSignupRejectedEmail(toAddress string, data SignupRejectedData) error {
return s.sendTemplate(signupRejectedTemplate, signupRejectedSubject, data, toAddress)
}
func (s *noopSender) sendTemplate(template string, subject string, data any, toAddresses ...string) error {
buf := &bytes.Buffer{}
if err := s.template.ExecuteTemplate(buf, template, data); err != nil {

View file

@ -53,6 +53,14 @@ type Sender interface {
// It is expected that the toAddresses have already been filtered to ensure
// that they all belong to active admins + moderators.
SendNewSignupEmail(toAddress []string, data NewSignupData) error
// SendSignupApprovedEmail sends an email to the given address
// that their sign-up request has been approved by a moderator.
SendSignupApprovedEmail(toAddress string, data SignupApprovedData) error
// SendSignupRejectedEmail sends an email to the given address
// that their sign-up request has been rejected by a moderator.
SendSignupRejectedEmail(toAddress string, data SignupRejectedData) error
}
// NewSender returns a new email Sender interface with the given configuration, or an error if something goes wrong.

View file

@ -40,3 +40,39 @@ type NewSignupData struct {
func (s *sender) SendNewSignupEmail(toAddresses []string, data NewSignupData) error {
return s.sendTemplate(newSignupTemplate, newSignupSubject, data, toAddresses...)
}
var (
signupApprovedTemplate = "email_signup_approved.tmpl"
signupApprovedSubject = "GoToSocial Sign-Up Approved"
)
type SignupApprovedData struct {
// Username to be addressed.
Username string
// URL of the instance to present to the receiver.
InstanceURL string
// Name of the instance to present to the receiver.
InstanceName string
}
func (s *sender) SendSignupApprovedEmail(toAddress string, data SignupApprovedData) error {
return s.sendTemplate(signupApprovedTemplate, signupApprovedSubject, data, toAddress)
}
var (
signupRejectedTemplate = "email_signup_rejected.tmpl"
signupRejectedSubject = "GoToSocial Sign-Up Rejected"
)
type SignupRejectedData struct {
// Message to the rejected applicant.
Message string
// URL of the instance to present to the receiver.
InstanceURL string
// Name of the instance to present to the receiver.
InstanceName string
}
func (s *sender) SendSignupRejectedEmail(toAddress string, data SignupRejectedData) error {
return s.sendTemplate(signupRejectedTemplate, signupRejectedSubject, data, toAddress)
}

View file

@ -141,6 +141,10 @@ func (p *Processor) ProcessFromClientAPI(ctx context.Context, cMsg messages.From
// ACCEPT FOLLOW (request)
case ap.ActivityFollow:
return p.clientAPI.AcceptFollow(ctx, cMsg)
// ACCEPT PROFILE/ACCOUNT (sign-up)
case ap.ObjectProfile, ap.ActorPerson:
return p.clientAPI.AcceptAccount(ctx, cMsg)
}
// REJECT SOMETHING
@ -150,6 +154,10 @@ func (p *Processor) ProcessFromClientAPI(ctx context.Context, cMsg messages.From
// REJECT FOLLOW (request)
case ap.ActivityFollow:
return p.clientAPI.RejectFollowRequest(ctx, cMsg)
// REJECT PROFILE/ACCOUNT (sign-up)
case ap.ObjectProfile, ap.ActorPerson:
return p.clientAPI.RejectAccount(ctx, cMsg)
}
// UNDO SOMETHING
@ -685,3 +693,37 @@ func (p *clientAPI) MoveAccount(ctx context.Context, cMsg messages.FromClientAPI
return nil
}
func (p *clientAPI) AcceptAccount(ctx context.Context, cMsg messages.FromClientAPI) error {
newUser, ok := cMsg.GTSModel.(*gtsmodel.User)
if !ok {
return gtserror.Newf("%T not parseable as *gtsmodel.User", cMsg.GTSModel)
}
// Send "your sign-up has been approved" email to the new user.
if err := p.surface.emailUserSignupApproved(ctx, newUser); err != nil {
log.Errorf(ctx, "error emailing: %v", err)
}
return nil
}
func (p *clientAPI) RejectAccount(ctx context.Context, cMsg messages.FromClientAPI) error {
denied, ok := cMsg.GTSModel.(*gtsmodel.DeniedUser)
if !ok {
return gtserror.Newf("%T not parseable as *gtsmodel.DeniedUser", cMsg.GTSModel)
}
if !*denied.SendEmail {
// No need to send an
// email. Nothing to do.
return nil
}
// Send "your sign-up has been rejected" email to the denied user.
if err := p.surface.emailUserSignupRejected(ctx, denied); err != nil {
log.Errorf(ctx, "error emailing: %v", err)
}
return nil
}

View file

@ -129,6 +129,69 @@ func (s *surface) emailUserPleaseConfirm(ctx context.Context, user *gtsmodel.Use
return nil
}
// emailUserSignupApproved emails the given user
// to inform them their sign-up has been approved.
func (s *surface) emailUserSignupApproved(ctx context.Context, user *gtsmodel.User) error {
// User may have been approved without
// their email address being confirmed
// yet. Just send to whatever we have.
emailAddr := user.Email
if emailAddr == "" {
emailAddr = user.UnconfirmedEmail
}
instance, err := s.state.DB.GetInstance(ctx, config.GetHost())
if err != nil {
return gtserror.Newf("db error getting instance: %w", err)
}
// Assemble email contents and send the email.
if err := s.emailSender.SendSignupApprovedEmail(
user.UnconfirmedEmail,
email.SignupApprovedData{
Username: user.Account.Username,
InstanceURL: instance.URI,
InstanceName: instance.Title,
},
); err != nil {
return err
}
// Email sent, update the user
// entry with the emailed time.
now := time.Now()
user.LastEmailedAt = now
if err := s.state.DB.UpdateUser(
ctx,
user,
"last_emailed_at",
); err != nil {
return gtserror.Newf("error updating user entry after email sent: %w", err)
}
return nil
}
// emailUserSignupApproved emails the given user
// to inform them their sign-up has been approved.
func (s *surface) emailUserSignupRejected(ctx context.Context, deniedUser *gtsmodel.DeniedUser) error {
instance, err := s.state.DB.GetInstance(ctx, config.GetHost())
if err != nil {
return gtserror.Newf("db error getting instance: %w", err)
}
// Assemble email contents and send the email.
return s.emailSender.SendSignupRejectedEmail(
deniedUser.Email,
email.SignupRejectedData{
Message: deniedUser.Message,
InstanceURL: instance.URI,
InstanceName: instance.Title,
},
)
}
// emailAdminReportOpened emails all active moderators/admins
// of this instance that a new report has been created.
func (s *surface) emailAdminReportOpened(ctx context.Context, report *gtsmodel.Report) error {

View file

@ -27,4 +27,6 @@ To confirm your email, paste the following in your browser's address bar:
{{ .ConfirmLink }}
---
If you believe you've been sent this email in error, feel free to ignore it, or contact the administrator of {{ .InstanceURL -}}.

View file

@ -25,3 +25,7 @@ The report you submitted has now been closed.
{{ if .ActionTakenComment }}The moderator who closed the report left the following comment: {{ .ActionTakenComment }}
{{- else }}The moderator who closed the report did not leave a comment.{{ end }}
---
If you believe you've been sent this email in error, feel free to ignore it, or contact the administrator of {{ .InstanceURL -}}.

View file

@ -25,4 +25,6 @@ To reset your password, paste the following in your browser's address bar:
{{.ResetLink}}
---
If you believe you've been sent this email in error, feel free to ignore it, or contact the administrator of {{.InstanceURL}}.

View file

@ -0,0 +1,34 @@
{{- /*
// GoToSocial
// Copyright (C) GoToSocial Authors admin@gotosocial.org
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
Hello {{ .Username -}}!
You are receiving this mail because your request for an account on {{ .InstanceName }} has been approved by a moderator. Welcome!
If you have already confirmed your email address, you can now log in to your new account using a client application of your choice.
Some client applications known to work with GoToSocial are listed here: {{ .InstanceURL -}}#apps.
If you have not yet confirmed your email address, you will not be able to log in until you have done so.
Please check your inbox for the relevant email containing the confirmation link.
---
If you believe you've been sent this email in error, feel free to ignore it, or contact the administrator of {{ .InstanceURL -}}.

View file

@ -0,0 +1,28 @@
{{- /*
// GoToSocial
// Copyright (C) GoToSocial Authors admin@gotosocial.org
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ -}}
Hello!
You are receiving this mail because your request for an account on {{ .InstanceName }} has been rejected by a moderator.
{{ if .Message }}The moderator who handled the sign-up included the following message regarding this rejection: "{{- .Message -}}"{{ end }}
---
If you believe you've been sent this email in error, feel free to ignore it, or contact the administrator of {{ .InstanceURL -}}.