summaryrefslogtreecommitdiff
path: root/internal/processing/workers
diff options
context:
space:
mode:
authorLibravatar tobi <31960611+tsmethurst@users.noreply.github.com>2024-04-13 13:25:10 +0200
committerLibravatar GitHub <noreply@github.com>2024-04-13 13:25:10 +0200
commit89e0cfd8741b6763ca04e90558bccf4c3c380cfa (patch)
tree5858ada73473816fa1982f12717b66996d163f9d /internal/processing/workers
parent[performance] update GetAccountsByIDs() to use the new multi cache loader end... (diff)
downloadgotosocial-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.go72
-rw-r--r--internal/processing/workers/surfaceemail.go65
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 {