diff options
author | 2024-04-13 13:25:10 +0200 | |
---|---|---|
committer | 2024-04-13 13:25:10 +0200 | |
commit | 89e0cfd8741b6763ca04e90558bccf4c3c380cfa (patch) | |
tree | 5858ada73473816fa1982f12717b66996d163f9d /internal/processing/workers | |
parent | [performance] update GetAccountsByIDs() to use the new multi cache loader end... (diff) | |
download | gotosocial-89e0cfd8741b6763ca04e90558bccf4c3c380cfa.tar.xz |
[feature] Admin accounts endpoints; approve/reject sign-ups (#2826)
* update settings panels, add pending overview + approve/deny functions
* add admin accounts get, approve, reject
* send approved/rejected emails
* use signup URL
* docs!
* email
* swagger
* web linting
* fix email tests
* wee lil fixerinos
* use new paging logic for GetAccounts() series of admin endpoints, small changes to query building
* shuffle useAccountIDIn check *before* adding to query
* fix parse from toot react error
* use `netip.Addr`
* put valid slices in globals
* optimistic updates for account state
---------
Co-authored-by: kim <grufwub@gmail.com>
Diffstat (limited to 'internal/processing/workers')
-rw-r--r-- | internal/processing/workers/fromclientapi.go | 72 | ||||
-rw-r--r-- | internal/processing/workers/surfaceemail.go | 65 |
2 files changed, 136 insertions, 1 deletions
diff --git a/internal/processing/workers/fromclientapi.go b/internal/processing/workers/fromclientapi.go index ed513c331..37c330cf0 100644 --- a/internal/processing/workers/fromclientapi.go +++ b/internal/processing/workers/fromclientapi.go @@ -33,6 +33,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/processing/account" "github.com/superseriousbusiness/gotosocial/internal/state" "github.com/superseriousbusiness/gotosocial/internal/typeutils" + "github.com/superseriousbusiness/gotosocial/internal/util" ) // clientAPI wraps processing functions @@ -141,6 +142,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 +155,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 +694,66 @@ 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) + } + + // Mark user as approved + clear sign-up IP. + newUser.Approved = util.Ptr(true) + newUser.SignUpIP = nil + if err := p.state.DB.UpdateUser(ctx, newUser, "approved", "sign_up_ip"); err != nil { + // Error now means we should return without + // sending email + let admin try to approve again. + return gtserror.Newf("db error updating user %s: %w", newUser.ID, err) + } + + // 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 { + deniedUser, ok := cMsg.GTSModel.(*gtsmodel.DeniedUser) + if !ok { + return gtserror.Newf("%T not parseable as *gtsmodel.DeniedUser", cMsg.GTSModel) + } + + // Remove the account. + if err := p.state.DB.DeleteAccount(ctx, cMsg.TargetAccount.ID); err != nil { + log.Errorf(ctx, + "db error deleting account %s: %v", + cMsg.TargetAccount.ID, err, + ) + } + + // Remove the user. + if err := p.state.DB.DeleteUserByID(ctx, deniedUser.ID); err != nil { + log.Errorf(ctx, + "db error deleting user %s: %v", + deniedUser.ID, err, + ) + } + + // Store the deniedUser entry. + if err := p.state.DB.PutDeniedUser(ctx, deniedUser); err != nil { + log.Errorf(ctx, + "db error putting denied user %s: %v", + deniedUser.ID, err, + ) + } + + if *deniedUser.SendEmail { + // Send "your sign-up has been rejected" email to the denied user. + if err := p.surface.emailUserSignupRejected(ctx, deniedUser); err != nil { + log.Errorf(ctx, "error emailing: %v", err) + } + } + + return nil +} diff --git a/internal/processing/workers/surfaceemail.go b/internal/processing/workers/surfaceemail.go index c00b22c86..3a5b5e7f4 100644 --- a/internal/processing/workers/surfaceemail.go +++ b/internal/processing/workers/surfaceemail.go @@ -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( + emailAddr, + 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 { @@ -193,7 +256,7 @@ func (s *surface) emailAdminNewSignup(ctx context.Context, newUser *gtsmodel.Use SignupEmail: newUser.UnconfirmedEmail, SignupUsername: newUser.Account.Username, SignupReason: newUser.Reason, - SignupURL: "TODO", + SignupURL: instance.URI + "/settings/admin/accounts/" + newUser.AccountID, } if err := s.emailSender.SendNewSignupEmail(toAddresses, newSignupData); err != nil { |