diff options
author | 2024-04-11 11:45:53 +0200 | |
---|---|---|
committer | 2024-04-11 11:45:53 +0200 | |
commit | 9fb8a78f91adffd5f4d28df1270e407c25a7a16e (patch) | |
tree | d68200744e28d07e75a52bb0c9f6593c86a38a91 /internal/processing/workers | |
parent | [performance] massively improved ActivityPub delivery worker efficiency (#2812) (diff) | |
download | gotosocial-9fb8a78f91adffd5f4d28df1270e407c25a7a16e.tar.xz |
[feature] New user sign-up via web page (#2796)
* [feature] User sign-up form and admin notifs
* add chosen + filtered languages to migration
* remove stray comment
* chosen languages schmosen schmanguages
* proper error on local account missing
Diffstat (limited to 'internal/processing/workers')
-rw-r--r-- | internal/processing/workers/fromclientapi.go | 23 | ||||
-rw-r--r-- | internal/processing/workers/fromfediapi.go | 2 | ||||
-rw-r--r-- | internal/processing/workers/surfaceemail.go | 118 | ||||
-rw-r--r-- | internal/processing/workers/surfacenotify.go | 41 |
4 files changed, 136 insertions, 48 deletions
diff --git a/internal/processing/workers/fromclientapi.go b/internal/processing/workers/fromclientapi.go index c7e78fee2..ed513c331 100644 --- a/internal/processing/workers/fromclientapi.go +++ b/internal/processing/workers/fromclientapi.go @@ -209,18 +209,23 @@ func (p *Processor) ProcessFromClientAPI(ctx context.Context, cMsg messages.From } func (p *clientAPI) CreateAccount(ctx context.Context, cMsg messages.FromClientAPI) error { - account, ok := cMsg.GTSModel.(*gtsmodel.Account) + newUser, ok := cMsg.GTSModel.(*gtsmodel.User) if !ok { - return gtserror.Newf("%T not parseable as *gtsmodel.Account", cMsg.GTSModel) + return gtserror.Newf("%T not parseable as *gtsmodel.User", cMsg.GTSModel) + } + + // Notify mods of the new signup. + if err := p.surface.notifySignup(ctx, newUser); err != nil { + log.Errorf(ctx, "error notifying mods of new sign-up: %v", err) } - // Send a confirmation email to the newly created account. - user, err := p.state.DB.GetUserByAccountID(ctx, account.ID) - if err != nil { - return gtserror.Newf("db error getting user for account id %s: %w", account.ID, err) + // Send "new sign up" email to mods. + if err := p.surface.emailAdminNewSignup(ctx, newUser); err != nil { + log.Errorf(ctx, "error emailing new signup: %v", err) } - if err := p.surface.emailPleaseConfirm(ctx, user, account.Username); err != nil { + // Send "please confirm your address" email to the new user. + if err := p.surface.emailUserPleaseConfirm(ctx, newUser); err != nil { log.Errorf(ctx, "error emailing confirm: %v", err) } @@ -458,7 +463,7 @@ func (p *clientAPI) UpdateReport(ctx context.Context, cMsg messages.FromClientAP return nil } - if err := p.surface.emailReportClosed(ctx, report); err != nil { + if err := p.surface.emailUserReportClosed(ctx, report); err != nil { log.Errorf(ctx, "error emailing report closed: %v", err) } @@ -644,7 +649,7 @@ func (p *clientAPI) ReportAccount(ctx context.Context, cMsg messages.FromClientA } } - if err := p.surface.emailReportOpened(ctx, report); err != nil { + if err := p.surface.emailAdminReportOpened(ctx, report); err != nil { log.Errorf(ctx, "error emailing report opened: %v", err) } diff --git a/internal/processing/workers/fromfediapi.go b/internal/processing/workers/fromfediapi.go index 2fc3b4b26..7b0e72490 100644 --- a/internal/processing/workers/fromfediapi.go +++ b/internal/processing/workers/fromfediapi.go @@ -473,7 +473,7 @@ func (p *fediAPI) CreateFlag(ctx context.Context, fMsg messages.FromFediAPI) err // TODO: handle additional side effects of flag creation: // - notify admins by dm / notification - if err := p.surface.emailReportOpened(ctx, incomingReport); err != nil { + if err := p.surface.emailAdminReportOpened(ctx, incomingReport); err != nil { log.Errorf(ctx, "error emailing report opened: %v", err) } diff --git a/internal/processing/workers/surfaceemail.go b/internal/processing/workers/surfaceemail.go index a6c97f48f..c00b22c86 100644 --- a/internal/processing/workers/surfaceemail.go +++ b/internal/processing/workers/surfaceemail.go @@ -31,41 +31,9 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/uris" ) -func (s *surface) emailReportOpened(ctx context.Context, report *gtsmodel.Report) error { - instance, err := s.state.DB.GetInstance(ctx, config.GetHost()) - if err != nil { - return gtserror.Newf("error getting instance: %w", err) - } - - toAddresses, err := s.state.DB.GetInstanceModeratorAddresses(ctx) - if err != nil { - if errors.Is(err, db.ErrNoEntries) { - // No registered moderator addresses. - return nil - } - return gtserror.Newf("error getting instance moderator addresses: %w", err) - } - - if err := s.state.DB.PopulateReport(ctx, report); err != nil { - return gtserror.Newf("error populating report: %w", err) - } - - reportData := email.NewReportData{ - InstanceURL: instance.URI, - InstanceName: instance.Title, - ReportURL: instance.URI + "/settings/admin/reports/" + report.ID, - ReportDomain: report.Account.Domain, - ReportTargetDomain: report.TargetAccount.Domain, - } - - if err := s.emailSender.SendNewReportEmail(toAddresses, reportData); err != nil { - return gtserror.Newf("error emailing instance moderators: %w", err) - } - - return nil -} - -func (s *surface) emailReportClosed(ctx context.Context, report *gtsmodel.Report) error { +// emailUserReportClosed emails the user who created the +// given report, to inform them the report has been closed. +func (s *surface) emailUserReportClosed(ctx context.Context, report *gtsmodel.Report) error { user, err := s.state.DB.GetUserByAccountID(ctx, report.Account.ID) if err != nil { return gtserror.Newf("db error getting user: %w", err) @@ -104,7 +72,9 @@ func (s *surface) emailReportClosed(ctx context.Context, report *gtsmodel.Report return s.emailSender.SendReportClosedEmail(user.Email, reportClosedData) } -func (s *surface) emailPleaseConfirm(ctx context.Context, user *gtsmodel.User, username string) error { +// emailUserPleaseConfirm emails the given user +// to ask them to confirm their email address. +func (s *surface) emailUserPleaseConfirm(ctx context.Context, user *gtsmodel.User) error { if user.UnconfirmedEmail == "" || user.UnconfirmedEmail == user.Email { // User has already confirmed this @@ -130,7 +100,7 @@ func (s *surface) emailPleaseConfirm(ctx context.Context, user *gtsmodel.User, u if err := s.emailSender.SendConfirmEmail( user.UnconfirmedEmail, email.ConfirmData{ - Username: username, + Username: user.Account.Username, InstanceURL: instance.URI, InstanceName: instance.Title, ConfirmLink: confirmLink, @@ -158,3 +128,77 @@ func (s *surface) emailPleaseConfirm(ctx context.Context, user *gtsmodel.User, u return nil } + +// 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 { + instance, err := s.state.DB.GetInstance(ctx, config.GetHost()) + if err != nil { + return gtserror.Newf("error getting instance: %w", err) + } + + toAddresses, err := s.state.DB.GetInstanceModeratorAddresses(ctx) + if err != nil { + if errors.Is(err, db.ErrNoEntries) { + // No registered moderator addresses. + return nil + } + return gtserror.Newf("error getting instance moderator addresses: %w", err) + } + + if err := s.state.DB.PopulateReport(ctx, report); err != nil { + return gtserror.Newf("error populating report: %w", err) + } + + reportData := email.NewReportData{ + InstanceURL: instance.URI, + InstanceName: instance.Title, + ReportURL: instance.URI + "/settings/admin/reports/" + report.ID, + ReportDomain: report.Account.Domain, + ReportTargetDomain: report.TargetAccount.Domain, + } + + if err := s.emailSender.SendNewReportEmail(toAddresses, reportData); err != nil { + return gtserror.Newf("error emailing instance moderators: %w", err) + } + + return nil +} + +// emailAdminNewSignup emails all active moderators/admins of this +// instance that a new account sign-up has been submitted to the instance. +func (s *surface) emailAdminNewSignup(ctx context.Context, newUser *gtsmodel.User) error { + instance, err := s.state.DB.GetInstance(ctx, config.GetHost()) + if err != nil { + return gtserror.Newf("error getting instance: %w", err) + } + + toAddresses, err := s.state.DB.GetInstanceModeratorAddresses(ctx) + if err != nil { + if errors.Is(err, db.ErrNoEntries) { + // No registered moderator addresses. + return nil + } + return gtserror.Newf("error getting instance moderator addresses: %w", err) + } + + // Ensure user populated. + if err := s.state.DB.PopulateUser(ctx, newUser); err != nil { + return gtserror.Newf("error populating user: %w", err) + } + + newSignupData := email.NewSignupData{ + InstanceURL: instance.URI, + InstanceName: instance.Title, + SignupEmail: newUser.UnconfirmedEmail, + SignupUsername: newUser.Account.Username, + SignupReason: newUser.Reason, + SignupURL: "TODO", + } + + if err := s.emailSender.SendNewSignupEmail(toAddresses, newSignupData); err != nil { + return gtserror.Newf("error emailing instance moderators: %w", err) + } + + return nil +} diff --git a/internal/processing/workers/surfacenotify.go b/internal/processing/workers/surfacenotify.go index a8c36248c..9c82712f2 100644 --- a/internal/processing/workers/surfacenotify.go +++ b/internal/processing/workers/surfacenotify.go @@ -333,6 +333,45 @@ func (s *surface) notifyPollClose(ctx context.Context, status *gtsmodel.Status) return errs.Combine() } +func (s *surface) notifySignup(ctx context.Context, newUser *gtsmodel.User) error { + modAccounts, err := s.state.DB.GetInstanceModerators(ctx) + if err != nil { + if errors.Is(err, db.ErrNoEntries) { + // No registered + // mod accounts. + return nil + } + + // Real error. + return gtserror.Newf("error getting instance moderator accounts: %w", err) + } + + // Ensure user + account populated. + if err := s.state.DB.PopulateUser(ctx, newUser); err != nil { + return gtserror.Newf("db error populating new user: %w", err) + } + + if err := s.state.DB.PopulateAccount(ctx, newUser.Account); err != nil { + return gtserror.Newf("db error populating new user's account: %w", err) + } + + // Notify each moderator. + var errs gtserror.MultiError + for _, mod := range modAccounts { + if err := s.notify(ctx, + gtsmodel.NotificationSignup, + mod, + newUser.Account, + "", + ); err != nil { + errs.Appendf("error notifying moderator %s: %w", mod.ID, err) + continue + } + } + + return errs.Combine() +} + // notify creates, inserts, and streams a new // notification to the target account if it // doesn't yet exist with the given parameters. @@ -342,7 +381,7 @@ func (s *surface) notifyPollClose(ctx context.Context, status *gtsmodel.Status) // targets into this function without filtering // for non-local first. // -// targetAccountID and originAccountID must be +// targetAccount and originAccount must be // set, but statusID can be an empty string. func (s *surface) notify( ctx context.Context, |